\documentclass[12pt]{report}
\usepackage{geometry}
\geometry{a4paper,scale=0.8}
\usepackage{longtable}
\usepackage{url}
\usepackage{listings}
\usepackage{graphicx}
\usepackage{float}
\usepackage{titlesec}
\usepackage{CJK}
\begin{CJK}{UTF8}{gkai}
%\titleformat{\chapter}[hang]{\centering\Huge\bfseries}{\chaptername}{1em}{}
%\renewcommand{\chaptername}{第\CJKnumber{thechapter}章}
\title{A004 学习linux0.01的文件系统初始化}
\author{Chuzy}
\date{2020/05/03}

\lstset{
    basicstyle          =   \small\ttfamily,          % 基本代码风格
    keywordstyle        =   \bfseries,          % 关键字风格
    commentstyle        =   \rmfamily\itshape,  % 注释的风格，斜体
    stringstyle         =   \ttfamily,  % 字符串风格
    flexiblecolumns,                % 别问为什么，加上这个
    numbers             =   left,   % 行号的位置在左边
    showspaces          =   false,  % 是否显示空格，显示了有点乱，所以不现实了
    numberstyle         =   \ttfamily,    % 行号的样式，小五号，tt等宽字体
    showstringspaces    =   false,
    captionpos          =   t,      % 这段代码的名字所呈现的位置，t指的是top上面
    frame               =   lrtb,   % 显示边框
    columns         =   flexible,     
    breaklines      =   true,
    language        =  [ANSI]C,
    escapeinside=``
}


%以上部分叫做"导言区",下面才开始写正文
\begin{document}

%先插入标题
\maketitle
\tableofcontents
\newpage 
\chapter{概述}
在003版本中，我们从内核态进入用户态，在004版本中，我们将初始化硬盘，安装文件系统，增加用户态的打印函数。
\begin{figure}[htbp]
\centering
\includegraphics[scale=0.5]{fig/36.png}
\caption{004版本运行结果}
\label{fig:Version 004}
\end{figure}
\chapter{流程图}
为了保持清晰，相对0.003版本没有变化的文件，将不在列出。
\begin{longtable}{|l|l|p{5cm}|p{3cm}|} 
\caption{0.003版本的文件}  
\label{tab: 0.004 files} \\ 
\hline 目录&文件名&作用&变化 \\
\hline / & Makefile & 增加了lib目录下文件的处理 & 变化\\ 
\hline  /init & main.c & 增加了trap和sched的初始化 & 变化\\
\hline  /kernel & Makefile & 增加了新的内核文件 & 变化\\
\hline  
\end{longtable}  
\chapter{初始化流程控制源码init/main.c}
\section{main函数}
相对003版本，增加了调用buffer\_init，hd\_init 函数，为安装文件系统做准备。
\begin{lstlisting}
int main(void)
{
    tty_init();
    trap_init();
    sched_init();
    buffer_init();
    hd_init();
    sti();
    move_to_user_mode();
    if (!fork()) {
        init();
    }
    for(;;) pause();
    return 0;
}
\end{lstlisting}
\section{init函数}
安装文件系统在用户态进行。在init函数中，通过setup加载ROOT\_DEV， 在这里我们调用了printf进行打印输出，而不再是printk函数，我们现在是在用户态打印输出。
\begin{lstlisting}[breaklines]

void init(void)
{
	setup();
	(void) open("/dev/tty0",O_RDWR,0);
	(void) dup(0);
	(void) dup(0);
	printf("Ok, printf from user mode.\n\r");	
	printf("%d buffers = %d bytes buffer space\n\r",NR_BUFFERS,
		NR_BUFFERS*BLOCK_SIZE);
	for(;;);
}
\end{lstlisting}
\section{printf函数}
用户态的打印输出函数。
\begin{lstlisting}[breaklines]
static char printbuf[1024];
static int printf(const char *fmt, ...)
{
        va_list args;
        int i;

        va_start(args, fmt);
    	i=vsprintf(printbuf, fmt, args);
        write(1,printbuf,i);
        va_end(args);
        return i;
}
\end{lstlisting}
\chapter{文件高速缓存源码fs/buffer.c}
\section{全局变量}
\paragraph{1} end为代码段结束位置，由Makefile写入？；
\paragraph{2} 然后根据LDT中代码段的基地址，得到连续地址；
\paragraph{3} 然后根以4K为单位做内存的写校验；
\paragraph{4} 在内存写校验中做写时复制；
\begin{lstlisting}[breaklines]
#include <linux/config.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <asm/system.h>

#if (BUFFER_END & 0xfff)
#error "Bad BUFFER_END value"
#endif

#if (BUFFER_END > 0xA0000 && BUFFER_END <= 0x100000)
#error "Bad BUFFER_END value"
#endif

extern int end;
struct buffer_head * start_buffer = (struct buffer_head *) &end;
struct buffer_head * hash_table[NR_HASH];
static struct buffer_head * free_list;
static struct task_struct * buffer_wait = NULL;
int NR_BUFFERS = 0;
\end{lstlisting}
\section{wait\_on\_buffer函数}
\paragraph{1} 首先关中断，然后判断buffer是否被lock，如果是，就进入等待状态；
\paragraph{2} 从等待状态中出来后，如果buffer仍被lock，继续等待；
\paragraph{3} 如果buffer已经不再被lock，则开中断，这里开关中断的目的，是让当前任务不再处理中断，其他任务仍可继续处理中断；
\begin{lstlisting}[breaklines]
static inline void wait_on_buffer(struct buffer_head * bh)
{
        cli();
        while (bh->b_lock)
                sleep_on(&bh->b_wait);
        sti();
}
\end{lstlisting}
\section{sys\_sync函数}
\paragraph{1} 首先将inode的变化同步到buffer block中；
\paragraph{2} 然后同步所有buffer block到设备中。
\begin{lstlisting}[breaklines]
int sys_sync(void)
{
        int i;
        struct buffer_head * bh;

        sync_inodes();          /* write out inodes into buffers */
        bh = start_buffer;
        for (i=0 ; i<NR_BUFFERS ; i++,bh++) {
                wait_on_buffer(bh);
                if (bh->b_dirt)
                        ll_rw_block(WRITE,bh);
        }
        return 0;
}
\end{lstlisting}
\section{sync\_dev函数}
\paragraph{1} 查找所有buffer head，如果关联到对应的设备，且b\_dirt置位，则调用底层写函数将缓冲内容同步到设备上。
\begin{lstlisting}[breaklines]
static int sync_dev(int dev)
{
        int i;
        struct buffer_head * bh;

        bh = start_buffer;
        for (i=0 ; i<NR_BUFFERS ; i++,bh++) {
                if (bh->b_dev != dev)
                        continue;
                wait_on_buffer(bh);
                if (bh->b_dirt)
                        ll_rw_block(WRITE,bh);
        }
        return 0;
}

\end{lstlisting}
\section{remove\_from\_queues函数}
\paragraph{1} 首先将buffer head从hash队列中移除；
\paragraph{2} 然后将buffer head从freelist中移除，移除的好处似乎是其他人无法再通过freelist找到该buffer head，反正之后还会再通过insert函数将该buffer head插入到freelist中。
\begin{lstlisting}[breaklines]
#define _hashfn(dev,block) (((unsigned)(dev^block))%NR_HASH)
#define hash(dev,block) hash_table[_hashfn(dev,block)]

static inline void remove_from_queues(struct buffer_head * bh)
{
/* remove from hash-queue */
        if (bh->b_next)
                bh->b_next->b_prev = bh->b_prev;
        if (bh->b_prev)
                bh->b_prev->b_next = bh->b_next;
        if (hash(bh->b_dev,bh->b_blocknr) == bh)
                hash(bh->b_dev,bh->b_blocknr) = bh->b_next;
/* remove from free list */
        if (!(bh->b_prev_free) || !(bh->b_next_free))
                panic("Free block list corrupted");
        bh->b_prev_free->b_next_free = bh->b_next_free;
        bh->b_next_free->b_prev_free = bh->b_prev_free;
        if (free_list == bh)
                free_list = bh->b_next_free;
}
\end{lstlisting}
\section{insert\_into\_queues函数}
\paragraph{1} 首先把buffer head节点放到free list的队尾；
\paragraph{2} 然后buffer head节点插入到hash表的最前面；
\paragraph{3} 如果设备号为0,似乎只有一个buffer head；
\paragraph{4} 最后一条语句前似乎应增加一条(b\_next不为null的判断)。
\begin{lstlisting}[breaklines]
static inline void insert_into_queues(struct buffer_head * bh)
{
/* put at end of free list */
        bh->b_next_free = free_list;
        bh->b_prev_free = free_list->b_prev_free;
        free_list->b_prev_free->b_next_free = bh;
        free_list->b_prev_free = bh;
/* put the buffer in new hash-queue if it has a device */
        bh->b_prev = NULL;
        bh->b_next = NULL;
        if (!bh->b_dev)
                return;
        bh->b_next = hash(bh->b_dev,bh->b_blocknr);
        hash(bh->b_dev,bh->b_blocknr) = bh;
        bh->b_next->b_prev = bh;
}

\end{lstlisting}
\section{find\_buffer函数}
\paragraph{1} 首先计算hash值，根据hash值看对应的buffer head队列是否为空；
\paragraph{2} 队列为空意味着该block没有buffer过，直接返回；
\paragraph{3} 队列不为空，则逐项检查队列中哪一个buffer block是要查找的block。
\begin{lstlisting}[breaklines]
static struct buffer_head * find_buffer(int dev, int block)
{               
        struct buffer_head * tmp;

        for (tmp = hash(dev,block) ; tmp != NULL ; tmp = tmp->b_next)
                if (tmp->b_dev==dev && tmp->b_blocknr==block)
                        return tmp;
        return NULL;
}
\end{lstlisting}
\section{get\_hash\_table函数}
\paragraph{1} 如果没有找到已经存在的buffer block，则直接返回null；
\paragraph{2} 如果找到，该block的引用次数+1, 并等待获得锁；
\paragraph{3} 获得锁后再次检查是否还是对应的buffer block，如对应则返回；
\paragraph{4} 否则释放对应的buffer block，重新检查；
\begin{lstlisting}[breaklines]
struct buffer_head * get_hash_table(int dev, int block)
{
        struct buffer_head * bh;

repeat:
        if (!(bh=find_buffer(dev,block)))
                return NULL;
        bh->b_count++;
        wait_on_buffer(bh);
        if (bh->b_dev != dev || bh->b_blocknr != block) {
                brelse(bh);
                goto repeat;
        }
        return bh;
}

\end{lstlisting}
\section{getblk函数}
\paragraph{1} 如果在hash表中找到对应的buffer block，则直接返回；
\paragraph{2} 从free\_list头部开始尝试获得一个空闲节点，如果节点的b\_count为0,则再等待获得锁之后，再进行一次检查，若还等于0,则找到一个节点；
\paragraph{3} 如果找到的节点，tmp，为null......实际不可能发生；
\paragraph{4} 将找到的节点的count数+1, 然后移出空闲队列；
\paragraph{5} 若数据标志为脏，则获取锁，并尝试将数据同步到设备中；
\paragraph{6} 再检查一遍是否有人使用了此节点，若有，则放弃，重新尝试；
\paragraph{7} 若一切正常，将此节点插入hash队列中。
\begin{lstlisting}[breaklines]
struct buffer_head * getblk(int dev,int block)
{
        struct buffer_head * tmp;

repeat:
        if (tmp=get_hash_table(dev,block))
                return tmp;
        tmp = free_list;
        do {
                if (!tmp->b_count) {
                        wait_on_buffer(tmp);    /* we still have to wait */
                        if (!tmp->b_count)      /* on it, it might be dirty */
                                break;
                }
                tmp = tmp->b_next_free;
        } while (tmp != free_list || (tmp=NULL));
        /* Kids, don't try THIS at home ^^^^^. Magic */
        if (!tmp) {
                printk("Sleeping on free buffer ..");
                sleep_on(&buffer_wait);
                printk("ok\n");
                goto repeat;
        }
        tmp->b_count++;
        remove_from_queues(tmp);
        if (tmp->b_dirt)
                sync_dev(tmp->b_dev);
/* update buffer contents */
        tmp->b_dev=dev;
        tmp->b_blocknr=block;
        tmp->b_dirt=0;
        tmp->b_uptodate=0;
/* NOTE!! While we possibly slept in sync_dev(), somebody else might have
 * added "this" block already, so check for that. Thank God for goto's.
 */
        if (find_buffer(dev,block)) {
                tmp->b_dev=0;           /* ok, someone else has beaten us */
                tmp->b_blocknr=0;       /* to it - free this block and */
                tmp->b_count=0;         /* try again */
                insert_into_queues(tmp);
                goto repeat;
        }
        insert_into_queues(tmp);
        return tmp;
}
\end{lstlisting}
\section{brelse函数}
\paragraph{1} 首先等待该buffer block解锁；
\paragraph{2} 然后将该buffer block使用计数--；
\paragraph{3} 唤醒等待空闲buffer block的进程；
\begin{lstlisting}[breaklines]
void brelse(struct buffer_head * buf)
{
        if (!buf)
                return;
        wait_on_buffer(buf);
        if (!(buf->b_count--))
                panic("Trying to free free buffer");
        wake_up(&buffer_wait);
}
\end{lstlisting}
\section{bread函数}
\paragraph{1} 根据要求读的dev和block，找到对应的buffer block\_head；
\paragraph{2} 如果buffer中的block内容是最新的，直接返回buffer block中的内容；
\paragraph{3} 调用底层读block函数；
\paragraph{4} 如果buffer中的block内容更新成功，则返回buffer block中的内容，否则读取失败，释放对应的buffer block。
\begin{lstlisting}[breaklines]
struct buffer_head * bread(int dev,int block)
{
        struct buffer_head * bh;

        if (!(bh=getblk(dev,block)))
                panic("bread: getblk returned NULL\n");
        if (bh->b_uptodate)
                return bh;
        ll_rw_block(READ,bh);
        if (bh->b_uptodate)
                return bh;
        brelse(bh);
        return (NULL);
}
\end{lstlisting}
\chapter{硬盘驱动程序源码fs/hd.c}
\section{全局变量}
\begin{lstlisting}[breaklines]
#include <linux/config.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/hdreg.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/segment.h>

/*
 * This code handles all hd-interrupts, and read/write requests to
 * the hard-disk. It is relatively straigthforward (not obvious maybe,
 * but interrupts never are), while still being efficient, and never
 * disabling interrupts (except to overcome possible race-condition).
 * The elevator block-seek algorithm doesn't need to disable interrupts
 * due to clever programming.
 */

/* Max read/write errors/sector */
#define MAX_ERRORS	5
#define MAX_HD		2
#define NR_REQUEST	32

/*
 *  This struct defines the HD's and their types.
 *  Currently defined for CP3044's, ie a modified
 *  type 17.
 */
static struct hd_i_struct{
	int head,sect,cyl,wpcom,lzone,ctl;
	} hd_info[]= { HD_TYPE };

#define NR_HD ((sizeof (hd_info))/(sizeof (struct hd_i_struct)))

static struct hd_struct {
	long start_sect;
	long nr_sects;
} hd[5*MAX_HD]={{0,0},};

static struct hd_request {
	int hd;		/* -1 if no request */
	int nsector;
	int sector;
	int head;
	int cyl;
	int cmd;
	int errors;
	struct buffer_head * bh;
	struct hd_request * next;
} request[NR_REQUEST];

#define IN_ORDER(s1,s2) \
((s1)->hd<(s2)->hd || (s1)->hd==(s2)->hd && \
((s1)->cyl<(s2)->cyl || (s1)->cyl==(s2)->cyl && \
((s1)->head<(s2)->head || (s1)->head==(s2)->head && \
((s1)->sector<(s2)->sector))))

static struct hd_request * this_request = NULL;

static int sorting=0;

static void do_request(void);
static void reset_controller(void);
static void rw_abs_hd(int rw,unsigned int nr,unsigned int sec,unsigned int head,
	unsigned int cyl,struct buffer_head * bh);
void hd_init(void);

#define port_read(port,buf,nr) \
__asm__("cld;rep;insw"::"d" (port),"D" (buf),"c" (nr))

#define port_write(port,buf,nr) \
__asm__("cld;rep;outsw"::"d" (port),"S" (buf),"c" (nr))

extern void hd_interrupt(void);

static struct task_struct * wait_for_request=NULL;
\end{lstlisting}
\section{look\_buffer函数}
\paragraph{1} 从start\_buffer到BUFFER\_END之间为buffer区，从buffer区的头部开始分配buffer\_head链表，从buffer区的后部从后往前分配buffer block，最后得到可分配的block总数；
\paragraph{2} 分配buffer block时注意跳过0xA0000--0x100000之间的BIOS ROM地址空间；
\paragraph{3} buffer\_head链表中的b\_data指向分配buffer block, 初始化时，buffer\_head节点通过b\_prev\_free和b\_next\_free组成一个双向循环链表。free\_list指向表头，其pre指向表尾，表尾的next指向free\_list；
\paragraph{4} 每个buffer head节点的b\_prev和b\_next指向相同hash值的节点位置，初始化为null，最后初始化HASH表，所有表项置为null；
\begin{lstlisting}[breaklines]

static inline void lock_buffer(struct buffer_head * bh)
{
	if (bh->b_lock)
		printk("hd.c: buffer multiply locked\n");
	bh->b_lock=1;
}

static inline void unlock_buffer(struct buffer_head * bh)
{
	if (!bh->b_lock)
		printk("hd.c: free buffer being unlocked\n");
	bh->b_lock=0;
	wake_up(&bh->b_wait);
}
\end{lstlisting}
\section{wait\_on\_buffer函数}
\paragraph{1} 从start\_buffer到BUFFER\_END之间为buffer区，从buffer区的头部开始分配buffer\_head链表，从buffer区的后部从后往前分配buffer block，最后得到可分配的block总数；
\paragraph{2} 分配buffer block时注意跳过0xA0000--0x100000之间的BIOS ROM地址空间；
\paragraph{3} buffer\_head链表中的b\_data指向分配buffer block, 初始化时，buffer\_head节点通过b\_prev\_free和b\_next\_free组成一个双向循环链表。free\_list指向表头，其pre指向表尾，表尾的next指向free\_list；
\paragraph{4} 每个buffer head节点的b\_prev和b\_next指向相同hash值的节点位置，初始化为null，最后初始化HASH表，所有表项置为null；
\begin{lstlisting}[breaklines]
static inline void wait_on_buffer(struct buffer_head * bh)
{
	cli();
	while (bh->b_lock)
		sleep_on(&bh->b_wait);
	sti();
}

void rw_hd(int rw, struct buffer_head * bh)
{
	unsigned int block,dev;
	unsigned int sec,head,cyl;

	block = bh->b_blocknr << 1;
	dev = MINOR(bh->b_dev);
	if (dev >= 5*NR_HD || block+2 > hd[dev].nr_sects)
		return;
	block += hd[dev].start_sect;
	dev /= 5;
	__asm__("divl %4":"=a" (block),"=d" (sec):"0" (block),"1" (0),
		"r" (hd_info[dev].sect));
	__asm__("divl %4":"=a" (cyl),"=d" (head):"0" (block),"1" (0),
		"r" (hd_info[dev].head));
	rw_abs_hd(rw,dev,sec+1,head,cyl,bh);
}
\end{lstlisting}
\section{sys\_setup函数}
\paragraph{1} 遍历所有硬盘，读取每块硬盘的bootSector；
\paragraph{2} 遍历硬盘上的所有分区表，将分区表内容记录到hd结构中；
\paragraph{3} 安装root文件系统；
\begin{lstlisting}[breaklines]
/* This may be used only once, enforced by 'static int callable' */
int sys_setup(void)
{
	static int callable = 1;
	int i,drive;
	struct partition *p;

	if (!callable)
		return -1;
	callable = 0;
	for (drive=0 ; drive<NR_HD ; drive++) {
		rw_abs_hd(READ,drive,1,0,0,(struct buffer_head *) start_buffer);
		if (!start_buffer->b_uptodate) {
			printk("Unable to read partition table of drive %d\n\r",
				drive);
			panic("");
		}
		if (start_buffer->b_data[510] != 0x55 || (unsigned char)
		    start_buffer->b_data[511] != 0xAA) {
			printk("Bad partition table on drive %d\n\r",drive);
			panic("");
		}
		p = 0x1BE + (void *)start_buffer->b_data;
		for (i=1;i<5;i++,p++) {
			hd[i+5*drive].start_sect = p->start_sect;
			hd[i+5*drive].nr_sects = p->nr_sects;
		}
	}
	printk("Partition table%s ok.\n\r",(NR_HD>1)?"s":"");
	mount_root();
	return (0);
}

/*
 * This is the pointer to a routine to be executed at every hd-interrupt.
 * Interesting way of doing things, but should be rather practical.
 */
void (*do_hd)(void) = NULL;

static int controller_ready(void)
{
	int retries=1000;

	while (--retries && (inb(HD_STATUS)&0xc0)!=0x40);
	return (retries);
}

static int win_result(void)
{
	int i=inb(HD_STATUS);

	if ((i & (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT))
		== (READY_STAT | SEEK_STAT))
		return(0); /* ok */
	if (i&1) i=inb(HD_ERROR);
	return (1);
}
\end{lstlisting}
\section{hd\_out函数}
\paragraph{1} 从start\_buffer到BUFFER\_END之间为buffer区，从buffer区的头部开始分配buffer\_head链表，从buffer区的后部从后往前分配buffer block，最后得到可分配的block总数；
\paragraph{2} 分配buffer block时注意跳过0xA0000--0x100000之间的BIOS ROM地址空间；
\paragraph{3} buffer\_head链表中的b\_data指向分配buffer block, 初始化时，buffer\_head节点通过b\_prev\_free和b\_next\_free组成一个双向循环链表。free\_list指向表头，其pre指向表尾，表尾的next指向free\_list；
\paragraph{4} 每个buffer head节点的b\_prev和b\_next指向相同hash值的节点位置，初始化为null，最后初始化HASH表，所有表项置为null；
\begin{lstlisting}[breaklines]

static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
		unsigned int head,unsigned int cyl,unsigned int cmd,
		void (*intr_addr)(void))
{
	register int port asm("dx");

	if (drive>1 || head>15)
		panic("Trying to write bad sector");
	if (!controller_ready())
		panic("HD controller not ready");
	do_hd = intr_addr;
	outb(_CTL,HD_CMD);
	port=HD_DATA;
	outb_p(_WPCOM,++port);
	outb_p(nsect,++port);
	outb_p(sect,++port);
	outb_p(cyl,++port);
	outb_p(cyl>>8,++port);
	outb_p(0xA0|(drive<<4)|head,++port);
	outb(cmd,++port);
}

static int drive_busy(void)
{
	unsigned int i;

	for (i = 0; i < 100000; i++)
		if (READY_STAT == (inb(HD_STATUS) & (BUSY_STAT | READY_STAT)))
			break;
	i = inb(HD_STATUS);
	i &= BUSY_STAT | READY_STAT | SEEK_STAT;
	if (i == READY_STAT | SEEK_STAT)
		return(0);
	printk("HD controller times out\n\r");
	return(1);
}

static void reset_controller(void)
{
	int	i;

	outb(4,HD_CMD);
	for(i = 0; i < 1000; i++) nop();
	outb(0,HD_CMD);
	for(i = 0; i < 10000 && drive_busy(); i++) /* nothing */;
	if (drive_busy())
		printk("HD-controller still busy\n\r");
	if((i = inb(ERR_STAT)) != 1)
		printk("HD-controller reset failed: %02x\n\r",i);
}

static void reset_hd(int nr)
{
	reset_controller();
	hd_out(nr,_SECT,_SECT,_HEAD-1,_CYL,WIN_SPECIFY,&do_request);
}

void unexpected_hd_interrupt(void)
{
	panic("Unexpected HD interrupt\n\r");
}

static void bad_rw_intr(void)
{
	int i = this_request->hd;

	if (this_request->errors++ >= MAX_ERRORS) {
		this_request->bh->b_uptodate = 0;
		unlock_buffer(this_request->bh);
		wake_up(&wait_for_request);
		this_request->hd = -1;
		this_request=this_request->next;
	}
	reset_hd(i);
}

static void read_intr(void)
{
	if (win_result()) {
		bad_rw_intr();
		return;
	}
	port_read(HD_DATA,this_request->bh->b_data+
		512*(this_request->nsector&1),256);
	this_request->errors = 0;
	if (--this_request->nsector)
		return;
	this_request->bh->b_uptodate = 1;
	this_request->bh->b_dirt = 0;
	wake_up(&wait_for_request);
	unlock_buffer(this_request->bh);
	this_request->hd = -1;
	this_request=this_request->next;
	do_request();
}

static void write_intr(void)
{
	if (win_result()) {
		bad_rw_intr();
		return;
	}
	if (--this_request->nsector) {
		port_write(HD_DATA,this_request->bh->b_data+512,256);
		return;
	}
	this_request->bh->b_uptodate = 1;
	this_request->bh->b_dirt = 0;
	wake_up(&wait_for_request);
	unlock_buffer(this_request->bh);
	this_request->hd = -1;
	this_request=this_request->next;
	do_request();
}
\end{lstlisting}
\section{do\_request函数}
\paragraph{1} 从start\_buffer到BUFFER\_END之间为buffer区，从buffer区的头部开始分配buffer\_head链表，从buffer区的后部从后往前分配buffer block，最后得到可分配的block总数；
\paragraph{2} 分配buffer block时注意跳过0xA0000--0x100000之间的BIOS ROM地址空间；
\paragraph{3} buffer\_head链表中的b\_data指向分配buffer block, 初始化时，buffer\_head节点通过b\_prev\_free和b\_next\_free组成一个双向循环链表。free\_list指向表头，其pre指向表尾，表尾的next指向free\_list；
\paragraph{4} 每个buffer head节点的b\_prev和b\_next指向相同hash值的节点位置，初始化为null，最后初始化HASH表，所有表项置为null；
\begin{lstlisting}[breaklines]

static void do_request(void)
{
	int i,r;

	if (sorting)
		return;
	if (!this_request) {
		do_hd=NULL;
		return;
	}
	if (this_request->cmd == WIN_WRITE) {
		hd_out(this_request->hd,this_request->nsector,this_request->
			sector,this_request->head,this_request->cyl,
			this_request->cmd,&write_intr);
		for(i=0 ; i<3000 && !(r=inb_p(HD_STATUS)&DRQ_STAT) ; i++)
			/* nothing */ ;
		if (!r) {
			reset_hd(this_request->hd);
			return;
		}
		port_write(HD_DATA,this_request->bh->b_data+
			512*(this_request->nsector&1),256);
	} else if (this_request->cmd == WIN_READ) {
		hd_out(this_request->hd,this_request->nsector,this_request->
			sector,this_request->head,this_request->cyl,
			this_request->cmd,&read_intr);
	} else
		panic("unknown hd-command");
}
\end{lstlisting}
\section{add\_request函数}
\paragraph{1} 从start\_buffer到BUFFER\_END之间为buffer区，从buffer区的头部开始分配buffer\_head链表，从buffer区的后部从后往前分配buffer block，最后得到可分配的block总数；
\paragraph{2} 分配buffer block时注意跳过0xA0000--0x100000之间的BIOS ROM地址空间；
\paragraph{3} buffer\_head链表中的b\_data指向分配buffer block, 初始化时，buffer\_head节点通过b\_prev\_free和b\_next\_free组成一个双向循环链表。free\_list指向表头，其pre指向表尾，表尾的next指向free\_list；
\paragraph{4} 每个buffer head节点的b\_prev和b\_next指向相同hash值的节点位置，初始化为null，最后初始化HASH表，所有表项置为null；
\begin{lstlisting}[breaklines]
/*
 * add-request adds a request to the linked list.
 * It sets the 'sorting'-variable when doing something
 * that interrupts shouldn't touch.
 */
static void add_request(struct hd_request * req)
{
	struct hd_request * tmp;

	if (req->nsector != 2)
		panic("nsector!=2 not implemented");
/*
 * Not to mess up the linked lists, we never touch the two first
 * entries (not this_request, as it is used by current interrups,
 * and not this_request->next, as it can be assigned to this_request).
 * This is not too high a price to pay for the ability of not
 * disabling interrupts.
 */
	sorting=1;
	if (!(tmp=this_request))
		this_request=req;
	else {
		if (!(tmp->next))
			tmp->next=req;
		else {
			tmp=tmp->next;
			for ( ; tmp->next ; tmp=tmp->next)
				if ((IN_ORDER(tmp,req) ||
				    !IN_ORDER(tmp,tmp->next)) &&
				    IN_ORDER(req,tmp->next))
					break;
			req->next=tmp->next;
			tmp->next=req;
		}
	}
	sorting=0;
/*
 * NOTE! As a result of sorting, the interrupts may have died down,
 * as they aren't redone due to locking with sorting=1. They might
 * also never have started, if this is the first request in the queue,
 * so we restart them if necessary.
 */
	if (!do_hd)
		do_request();
}
\end{lstlisting}
\section{rw\_abs\_hd函数}
\paragraph{1} 从start\_buffer到BUFFER\_END之间为buffer区，从buffer区的头部开始分配buffer\_head链表，从buffer区的后部从后往前分配buffer block，最后得到可分配的block总数；
\paragraph{2} 分配buffer block时注意跳过0xA0000--0x100000之间的BIOS ROM地址空间；
\paragraph{3} buffer\_head链表中的b\_data指向分配buffer block, 初始化时，buffer\_head节点通过b\_prev\_free和b\_next\_free组成一个双向循环链表。free\_list指向表头，其pre指向表尾，表尾的next指向free\_list；
\paragraph{4} 每个buffer head节点的b\_prev和b\_next指向相同hash值的节点位置，初始化为null，最后初始化HASH表，所有表项置为null；
\begin{lstlisting}[breaklines]

void rw_abs_hd(int rw,unsigned int nr,unsigned int sec,unsigned int head,
	unsigned int cyl,struct buffer_head * bh)
{
	struct hd_request * req;

	if (rw!=READ && rw!=WRITE)
		panic("Bad hd command, must be R/W");
	lock_buffer(bh);
repeat:
	for (req=0+request ; req<NR_REQUEST+request ; req++)
		if (req->hd<0)
			break;
	if (req==NR_REQUEST+request) {
		sleep_on(&wait_for_request);
		goto repeat;
	}
	req->hd=nr;
	req->nsector=2;
	req->sector=sec;
	req->head=head;
	req->cyl=cyl;
	req->cmd = ((rw==READ)?WIN_READ:WIN_WRITE);
	req->bh=bh;
	req->errors=0;
	req->next=NULL;
	add_request(req);
	wait_on_buffer(bh);
}
\end{lstlisting}
\section{hd\_init函数}
\paragraph{1} 首先初始化request数组，request中保存硬盘访问记录，最多可以保存32个访问记录；
\paragraph{2} 然后初始化hd数组，这里保存硬盘分区信息，一块硬盘有其本身的start\_sector和最多4个分区的start\_sector和sector总数组成；
\paragraph{3} 注册硬盘产生的中断的处理程序；
\paragraph{4} 复位主8259A的int2的屏蔽位和从8259A上的屏蔽位；
\begin{lstlisting}[breaklines]
void hd_init(void)
{
	int i;

	for (i=0 ; i<NR_REQUEST ; i++) {
		request[i].hd = -1;
		request[i].next = NULL;
	}
	for (i=0 ; i<NR_HD ; i++) {
		hd[i*5].start_sect = 0;
		hd[i*5].nr_sects = hd_info[i].head*
				hd_info[i].sect*hd_info[i].cyl;
	}
	set_trap_gate(0x2E,&hd_interrupt);
	outb_p(inb_p(0x21)&0xfb,0x21);
	outb(inb_p(0xA1)&0xbf,0xA1);
}
\end{lstlisting}
\chapter{超级块处理源码fs/supper.c}
\section{全局变量}
\paragraph{1} super\_block数组，最多支持8个，对应8个文件系统；
\begin{lstlisting}[breaklines]
/*
 * super.c contains code to handle the super-block tables.
 */
#include <linux/config.h>
#include <linux/sched.h>
#include <linux/kernel.h>

/* set_bit uses setb, as gas doesn't recognize setc */
#define set_bit(bitnr,addr) ({ \
register int __res __asm__("ax"); \
__asm__("bt %2,%3;setb %%al":"=a" (__res):"a" (0),"r" (bitnr),"m" (*(addr))); \
__res; })

struct super_block super_block[NR_SUPER];
\end{lstlisting}
\section{do\_mount函数}
\paragraph{1} 首先要找到一个空闲的super block，for下面的检查语句有一个bug；
\paragraph{2} 然后读取要挂载设备的1号逻辑块；
\paragraph{3} 将包含1号逻辑块内容的buffer block复制到super block后，释放buffer block；
\paragraph{4} 按照s\_imap\_blocks和s\_zmap\_blocks指示读取对应的逻辑块；注意跳过保存boot信息的0号逻辑块和保存super block的1号逻辑块；
\paragraph{5} 将imap和zmap对应的buffer block的最低位置1；
\paragraph{6} 初始化其他super block信息。
\begin{lstlisting}[breaklines]
struct super_block * do_mount(int dev)
{
	struct super_block * p;
	struct buffer_head * bh;
	int i,block;

	for(p = &super_block[0] ; p < &super_block[NR_SUPER] ; p++ )
		if (!(p->s_dev))
			break;
	p->s_dev = -1;		/* mark it in use */
	if (p >= &super_block[NR_SUPER])
		return NULL;
	if (!(bh = bread(dev,1)))
		return NULL;
	*p = *((struct super_block *) bh->b_data);
	brelse(bh);
	if (p->s_magic != SUPER_MAGIC) {
		p->s_dev = 0;
		return NULL;
	}
	for (i=0;i<I_MAP_SLOTS;i++)
		p->s_imap[i] = NULL;
	for (i=0;i<Z_MAP_SLOTS;i++)
		p->s_zmap[i] = NULL;
	block=2;
	for (i=0 ; i < p->s_imap_blocks ; i++)
		if (p->s_imap[i]=bread(dev,block))
			block++;
		else
			break;
	for (i=0 ; i < p->s_zmap_blocks ; i++)
		if (p->s_zmap[i]=bread(dev,block))
			block++;
		else
			break;
	if (block != 2+p->s_imap_blocks+p->s_zmap_blocks) {
		for(i=0;i<I_MAP_SLOTS;i++)
			brelse(p->s_imap[i]);
		for(i=0;i<Z_MAP_SLOTS;i++)
			brelse(p->s_zmap[i]);
		p->s_dev=0;
		return NULL;
	}
	p->s_imap[0]->b_data[0] |= 1;
	p->s_zmap[0]->b_data[0] |= 1;
	p->s_dev = dev;
	p->s_isup = NULL;
	p->s_imount = NULL;
	p->s_time = 0;
	p->s_rd_only = 0;
	p->s_dirt = 0;
	return p;
}
\end{lstlisting}
\section{mount\_root函数}
\paragraph{1} 初始化file\_table，系统最多可同时打开64个文件；
\paragraph{2} 初始化super\_block，最多8个，对应最大8个文件系统；
\paragraph{3} 然后挂载根设备，获得根设备上的1号inode；
\paragraph{4} 在super\_block中记录文件系统安装的inode和根目录的inode；
\paragraph{5} 在当前进程（初始进程）记录根目录和当前工作目录的inode；
\paragraph{6} 也即该inode被引用了4次；
\paragraph{7} s\_nzones指硬盘上的逻辑块数，系统最多65536个逻辑块，每个逻辑块对应1Kbyte的硬盘存储区；
\paragraph{8} p$->s$\_zmap[8]指向保存硬盘逻辑块位图的8个buffer block，每个buffer block对应个逻辑块，1Kbytes，对应8Kbits的位图，每个位图表示一个1Kbytes逻辑块的使用情况，因此对应8*1K*8*1K=64Mbys的硬盘；
\paragraph{9} p$->s$\_imap[8]指向保存硬盘逻辑块位图的8个buffer block，每个buffer block对应个逻辑块，1Kbytes，对应8Kbits的位图，每个位图表示一个1个inode的使用情况，因此最多对应8*1K*8=64K个inode；实际该硬盘上的inode数量则保存在p$->s$\_ninodes中。
\begin{lstlisting}[breaklines]
void mount_root(void)
{
	int i,free;
	struct super_block * p;
	struct m_inode * mi;

	if (32 != sizeof (struct d_inode))
		panic("bad i-node size");
	for(i=0;i<NR_FILE;i++)
		file_table[i].f_count=0;
	for(p = &super_block[0] ; p < &super_block[NR_SUPER] ; p++)
		p->s_dev = 0;
	if (!(p=do_mount(ROOT_DEV)))
		panic("Unable to mount root");
	if (!(mi=iget(ROOT_DEV,1)))
		panic("Unable to read root i-node");
	mi->i_count += 3 ;	/* NOTE! it is logically used 4 times, not 1 */
	p->s_isup = p->s_imount = mi;
	current->pwd = mi;
	current->root = mi;
	free=0;
	i=p->s_nzones;
	while (-- i >= 0)
		if (!set_bit(i&8191,p->s_zmap[i>>13]->b_data))
			free++;
	printk("%d/%d free blocks\n\r",free,p->s_nzones);
	free=0;
	i=p->s_ninodes+1;
	while (-- i >= 0)
		if (!set_bit(i&8191,p->s_imap[i>>13]->b_data))
			free++;
	printk("%d/%d free inodes\n\r",free,p->s_ninodes);
}
\end{lstlisting}
\chapter{文件打开操作源码fs/open.c}
\section{全局变量}
\begin{lstlisting}[breaklines]
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <utime.h>
#include <sys/stat.h>

#include <linux/sched.h>
#include <linux/tty.h>
#include <linux/kernel.h>
#include <asm/segment.h>

int sys_utime(char * filename, struct utimbuf * times)
{
	struct m_inode * inode;
	long actime,modtime;

	if (!(inode=namei(filename)))
		return -ENOENT;
	if (times) {
		actime = get_fs_long((unsigned long *) &times->actime);
		modtime = get_fs_long((unsigned long *) &times->modtime);
	} else
		actime = modtime = CURRENT_TIME;
	inode->i_atime = actime;
	inode->i_mtime = modtime;
	inode->i_dirt = 1;
	iput(inode);
	return 0;
}

int sys_access(const char * filename,int mode)
{
	struct m_inode * inode;
	int res;

	mode &= 0007;
	if (!(inode=namei(filename)))
		return -EACCES;
	res = inode->i_mode & 0777;
	iput(inode);
	if (!(current->euid && current->uid))
		if (res & 0111)
			res = 0777;
		else
			res = 0666;
	if (current->euid == inode->i_uid)
		res >>= 6;
	else if (current->egid == inode->i_gid)
		res >>= 6;
	if ((res & 0007 & mode) == mode)
		return 0;
	return -EACCES;
}

int sys_chdir(const char * filename)
{
	struct m_inode * inode;

	if (!(inode = namei(filename)))
		return -ENOENT;
	if (!S_ISDIR(inode->i_mode)) {
		iput(inode);
		return -ENOTDIR;
	}
	iput(current->pwd);
	current->pwd = inode;
	return (0);
}

int sys_chroot(const char * filename)
{
	struct m_inode * inode;

	if (!(inode=namei(filename)))
		return -ENOENT;
	if (!S_ISDIR(inode->i_mode)) {
		iput(inode);
		return -ENOTDIR;
	}
	iput(current->root);
	current->root = inode;
	return (0);
}

int sys_chmod(const char * filename,int mode)
{
	struct m_inode * inode;

	if (!(inode=namei(filename)))
		return -ENOENT;
	if (current->uid && current->euid)
		if (current->uid!=inode->i_uid && current->euid!=inode->i_uid) {
			iput(inode);
			return -EACCES;
		} else 
			mode = (mode & 0777) | (inode->i_mode & 07000);
	inode->i_mode = (mode & 07777) | (inode->i_mode & ~07777);
	inode->i_dirt = 1;
	iput(inode);
	return 0;
}

int sys_chown(const char * filename,int uid,int gid)
{
	struct m_inode * inode;

	if (!(inode=namei(filename)))
		return -ENOENT;
	if (current->uid && current->euid) {
		iput(inode);
		return -EACCES;
	}
	inode->i_uid=uid;
	inode->i_gid=gid;
	inode->i_dirt=1;
	iput(inode);
	return 0;
}
\end{lstlisting}
\section{sys\_open函数}
\paragraph{1} 在当前进程的文件表中找到一个空白表项，并记录进程退出时需要释放；
\paragraph{2} 调用open\_namei函数，找到文件对应的inode，并保存到进程的文件表中。
\begin{lstlisting}[breaklines]
int sys_open(const char * filename,int flag,int mode)
{
	struct m_inode * inode;
	struct file * f;
	int i,fd;

	mode &= 0777 & ~current->umask;
	for(fd=0 ; fd<NR_OPEN ; fd++)
		if (!current->filp[fd])
			break;
	if (fd>=NR_OPEN)
		return -EINVAL;
	current->close_on_exec &= ~(1<<fd);
	f=0+file_table;
	for (i=0 ; i<NR_FILE ; i++,f++)
		if (!f->f_count) break;
	if (i>=NR_FILE)
		return -EINVAL;
	(current->filp[fd]=f)->f_count++;
	if ((i=open_namei(filename,flag,mode,&inode))<0) {
		current->filp[fd]=NULL;
		f->f_count=0;
		return i;
	}
/* ttys are somewhat special (ttyxx major==4, tty major==5) */
	if (S_ISCHR(inode->i_mode))
		if (MAJOR(inode->i_zone[0])==4) {
			if (current->leader && current->tty<0) {
				current->tty = MINOR(inode->i_zone[0]);
				tty_table[current->tty].pgrp = current->pgrp;
			}
		} else if (MAJOR(inode->i_zone[0])==5)
			if (current->tty<0) {
				iput(inode);
				current->filp[fd]=NULL;
				f->f_count=0;
				return -EPERM;
			}
	f->f_mode = inode->i_mode;
	f->f_flags = flag;
	f->f_count = 1;
	f->f_inode = inode;
	f->f_pos = 0;
	return (fd);
}
\end{lstlisting}
\section{sys\_creat函数}
\paragraph{1} super\_block数组，最多支持8个，对应8个文件系统；
\begin{lstlisting}[breaklines]
int sys_creat(const char * pathname, int mode)
{
	return sys_open(pathname, O_CREAT | O_TRUNC, mode);
}

int sys_close(unsigned int fd)
{	
	struct file * filp;

	if (fd >= NR_OPEN)
		return -EINVAL;
	current->close_on_exec &= ~(1<<fd);
	if (!(filp = current->filp[fd]))
		return -EINVAL;
	current->filp[fd] = NULL;
	if (filp->f_count == 0)
		panic("Close: file count is 0");
	if (--filp->f_count)
		return (0);
	iput(filp->f_inode);
	return (0);
}
\end{lstlisting}
\chapter{文件或目录名处理源码fs/namei.c}
\section{全局变量}
\begin{lstlisting}[breaklines]
#include <linux/sched.h>
#include <linux/kernel.h>
#include <asm/segment.h>

#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <const.h>
#include <sys/stat.h>
#define ACC_MODE(x) ("\004\002\006\377"[(x)&O_ACCMODE])

/*
 * comment out this line if you want names > NAME_LEN chars to be
 * truncated. Else they will be disallowed.
 */
/* #define NO_TRUNCATE */

#define MAY_EXEC 1
#define MAY_WRITE 2
#define MAY_READ 4

/*
 *	permission()
 *
 * is used to check for read/write/execute permissions on a file.
 * I don't know if we should look at just the euid or both euid and
 * uid, but that should be easily changed.
 */
static int permission(struct m_inode * inode,int mask)
{
	int mode = inode->i_mode;

/* special case: not even root can read/write a deleted file */
	if (inode->i_dev && !inode->i_nlinks)
		return 0;
	if (!(current->uid && current->euid))
		mode=0777;
	else if (current->uid==inode->i_uid || current->euid==inode->i_uid)
		mode >>= 6;
	else if (current->gid==inode->i_gid || current->egid==inode->i_gid)
		mode >>= 3;
	return mode & mask & 0007;
}
\end{lstlisting}
\section{match函数}
\paragraph{1} 由于整个namei的操作都在内核态的操作空间，不能用strncmp比较用户空间传进来的name；
\paragraph{2} fs段，指向用户态空间，在用户数据空间中进行比较；
\begin{lstlisting}[breaklines]
/*
 * ok, we cannot use strncmp, as the name is not in our data space.
 * Thus we'll have to use match. No big problem. Match also makes
 * some sanity tests.
 *
 * NOTE! unlike strncmp, match returns 1 for success, 0 for failure.
 */
static int match(int len,const char * name,struct dir_entry * de)
{
	register int same __asm__("ax");

	if (!de || !de->inode || len > NAME_LEN)
		return 0;
	if (len < NAME_LEN && de->name[len])
		return 0;
	__asm__("cld\n\t"
		"fs ; repe ; cmpsb\n\t"
		"setz %%al"
		:"=a" (same)
		:"0" (0),"S" ((long) name),"D" ((long) de->name),"c" (len)
		);
	return same;
}
\end{lstlisting}
\section{find\_entry函数}
\paragraph{1} 读取对应目录的inode的buffer block；
\paragraph{2} 遍历该block，匹配要查找的name；
\paragraph{3} 如果一个buffer block没有找到，遍历该inode的所有block。
\begin{lstlisting}[breaklines]
/*
 *	find_entry()
 *
 * finds and entry in the specified directory with the wanted name. It
 * returns the cache buffer in which the entry was found, and the entry
 * itself (as a parameter - res_dir). It does NOT read the inode of the
 * entry - you'll have to do that yourself if you want to.
 */
static struct buffer_head * find_entry(struct m_inode * dir,
	const char * name, int namelen, struct dir_entry ** res_dir)
{
	int entries;
	int block,i;
	struct buffer_head * bh;
	struct dir_entry * de;

#ifdef NO_TRUNCATE
	if (namelen > NAME_LEN)
		return NULL;
#else
	if (namelen > NAME_LEN)
		namelen = NAME_LEN;
#endif
	entries = dir->i_size / (sizeof (struct dir_entry));
	*res_dir = NULL;
	if (!namelen)
		return NULL;
	if (!(block = dir->i_zone[0]))
		return NULL;
	if (!(bh = bread(dir->i_dev,block)))
		return NULL;
	i = 0;
	de = (struct dir_entry *) bh->b_data;
	while (i < entries) {
		if ((char *)de >= BLOCK_SIZE+bh->b_data) {
			brelse(bh);
			bh = NULL;
			if (!(block = bmap(dir,i/DIR_ENTRIES_PER_BLOCK)) ||
			    !(bh = bread(dir->i_dev,block))) {
				i += DIR_ENTRIES_PER_BLOCK;
				continue;
			}
			de = (struct dir_entry *) bh->b_data;
		}
		if (match(namelen,name,de)) {
			*res_dir = de;
			return bh;
		}
		de++;
		i++;
	}
	brelse(bh);
	return NULL;
}
\end{lstlisting}
\section{add\_entry函数}
\paragraph{1} 根据输入的pathname的第一个字符是不是‘/’判断是从root还是当前工作目录开始查找；
\paragraph{2} 在while循环中遍历pathname，如果是一个目录，则找到对应的inode，；
\begin{lstlisting}[breaklines]
/*
 *	add_entry()
 *
 * adds a file entry to the specified directory, using the same
 * semantics as find_entry(). It returns NULL if it failed.
 *
 * NOTE!! The inode part of 'de' is left at 0 - which means you
 * may not sleep between calling this and putting something into
 * the entry, as someone else might have used it while you slept.
 */
static struct buffer_head * add_entry(struct m_inode * dir,
	const char * name, int namelen, struct dir_entry ** res_dir)
{
	int block,i;
	struct buffer_head * bh;
	struct dir_entry * de;

	*res_dir = NULL;
#ifdef NO_TRUNCATE
	if (namelen > NAME_LEN)
		return NULL;
#else
	if (namelen > NAME_LEN)
		namelen = NAME_LEN;
#endif
	if (!namelen)
		return NULL;
	if (!(block = dir->i_zone[0]))
		return NULL;
	if (!(bh = bread(dir->i_dev,block)))
		return NULL;
	i = 0;
	de = (struct dir_entry *) bh->b_data;
	while (1) {
		if ((char *)de >= BLOCK_SIZE+bh->b_data) {
			brelse(bh);
			bh = NULL;
			block = create_block(dir,i/DIR_ENTRIES_PER_BLOCK);
			if (!block)
				return NULL;
			if (!(bh = bread(dir->i_dev,block))) {
				i += DIR_ENTRIES_PER_BLOCK;
				continue;
			}
			de = (struct dir_entry *) bh->b_data;
		}
		if (i*sizeof(struct dir_entry) >= dir->i_size) {
			de->inode=0;
			dir->i_size = (i+1)*sizeof(struct dir_entry);
			dir->i_dirt = 1;
			dir->i_ctime = CURRENT_TIME;
		}
		if (!de->inode) {
			dir->i_mtime = CURRENT_TIME;
			for (i=0; i < NAME_LEN ; i++)
				de->name[i]=(i<namelen)?get_fs_byte(name+i):0;
			bh->b_dirt = 1;
			*res_dir = de;
			return bh;
		}
		de++;
		i++;
	}
	brelse(bh);
	return NULL;
}
\end{lstlisting}
\section{get\_dir函数}
\paragraph{1} 根据输入的pathname的第一个字符是不是‘/’判断是从root还是当前工作目录开始查找；
\paragraph{2} 在while循环中遍历pathname，如果是一个目录，则从当前的inode中找到对应目录的inode，然后还是下一级的查找；
\paragraph{2} 最终找到非目录或者字符串终止为止。
\begin{lstlisting}[breaklines]
/*
 *	get_dir()
 *
 * Getdir traverses the pathname until it hits the topmost directory.
 * It returns NULL on failure.
 */
static struct m_inode * get_dir(const char * pathname)
{
	char c;
	const char * thisname;
	struct m_inode * inode;
	struct buffer_head * bh;
	int namelen,inr,idev;
	struct dir_entry * de;

	if (!current->root || !current->root->i_count)
		panic("No root inode");
	if (!current->pwd || !current->pwd->i_count)
		panic("No cwd inode");
	if ((c=get_fs_byte(pathname))=='/') {
		inode = current->root;
		pathname++;
	} else if (c)
		inode = current->pwd;
	else
		return NULL;	/* empty name is bad */
	inode->i_count++;
	while (1) {
		thisname = pathname;
		if (!S_ISDIR(inode->i_mode) || !permission(inode,MAY_EXEC)) {
			iput(inode);
			return NULL;
		}
		for(namelen=0;(c=get_fs_byte(pathname++))&&(c!='/');namelen++)
			/* nothing */ ;
		if (!c)
			return inode;
		if (!(bh = find_entry(inode,thisname,namelen,&de))) {
			iput(inode);
			return NULL;
		}
		inr = de->inode;
		idev = inode->i_dev;
		brelse(bh);
		iput(inode);
		if (!(inode = iget(idev,inr)))
			return NULL;
	}
}
\end{lstlisting}
\section{dir\_namei函数}
\paragraph{1} 通过get\_dir检查目录名确实存在；
\paragraph{2} 保存文件名和长度。
\begin{lstlisting}[breaklines]
/*
 *	dir_namei()
 *
 * dir_namei() returns the inode of the directory of the
 * specified name, and the name within that directory.
 */
static struct m_inode * dir_namei(const char * pathname,
	int * namelen, const char ** name)
{
	char c;
	const char * basename;
	struct m_inode * dir;

	if (!(dir = get_dir(pathname)))
		return NULL;
	basename = pathname;
	while (c=get_fs_byte(pathname++))
		if (c=='/')
			basename=pathname;
	*namelen = pathname-basename-1;
	*name = basename;
	return dir;
}
\end{lstlisting}
\section{namei函数}
\paragraph{1} 通过dir\_namei得到最后一级目录所在的inode和文件名；
\paragraph{2} 在inode所在的buffer block里找到文件名对应的inode；
\begin{lstlisting}[breaklines]
/*
 *	namei()
 *
 * is used by most simple commands to get the inode of a specified name.
 * Open, link etc use their own routines, but this is enough for things
 * like 'chmod' etc.
 */
struct m_inode * namei(const char * pathname)
{
	const char * basename;
	int inr,dev,namelen;
	struct m_inode * dir;
	struct buffer_head * bh;
	struct dir_entry * de;

	if (!(dir = dir_namei(pathname,&namelen,&basename)))
		return NULL;
	if (!namelen)			/* special case: '/usr/' etc */
		return dir;
	bh = find_entry(dir,basename,namelen,&de);
	if (!bh) {
		iput(dir);
		return NULL;
	}
	inr = de->inode;
	dev = dir->i_dev;
	brelse(bh);
	iput(dir);
	dir=iget(dev,inr);
	if (dir) {
		dir->i_atime=CURRENT_TIME;
		dir->i_dirt=1;
	}
	return dir;
}
\end{lstlisting}
\section{open\_namei函数}
\paragraph{1} 通过dir\_namei得到最后一级目录所在的inode和文件名；
\paragraph{2} 得到对应文件名的inode；
\begin{lstlisting}[breaklines]
/*
 *	open_namei()
 *
 * namei for open - this is in fact almost the whole open-routine.
 */
int open_namei(const char * pathname, int flag, int mode,
	struct m_inode ** res_inode)
{
	const char * basename;
	int inr,dev,namelen;
	struct m_inode * dir, *inode;
	struct buffer_head * bh;
	struct dir_entry * de;

	if ((flag & O_TRUNC) && !(flag & O_ACCMODE))
		flag |= O_WRONLY;
	mode &= 0777 & ~current->umask;
	mode |= I_REGULAR;
	if (!(dir = dir_namei(pathname,&namelen,&basename)))
		return -ENOENT;
	if (!namelen) {			/* special case: '/usr/' etc */
		if (!(flag & (O_ACCMODE|O_CREAT|O_TRUNC))) {
			*res_inode=dir;
			return 0;
		}
		iput(dir);
		return -EISDIR;
	}
	bh = find_entry(dir,basename,namelen,&de);
	if (!bh) {
		if (!(flag & O_CREAT)) {
			iput(dir);
			return -ENOENT;
		}
		if (!permission(dir,MAY_WRITE)) {
			iput(dir);
			return -EACCES;
		}
		inode = new_inode(dir->i_dev);
		if (!inode) {
			iput(dir);
			return -ENOSPC;
		}
		inode->i_mode = mode;
		inode->i_dirt = 1;
		bh = add_entry(dir,basename,namelen,&de);
		if (!bh) {
			inode->i_nlinks--;
			iput(inode);
			iput(dir);
			return -ENOSPC;
		}
		de->inode = inode->i_num;
		bh->b_dirt = 1;
		brelse(bh);
		iput(dir);
		*res_inode = inode;
		return 0;
	}
	inr = de->inode;
	dev = dir->i_dev;
	brelse(bh);
	iput(dir);
	if (flag & O_EXCL)
		return -EEXIST;
	if (!(inode=iget(dev,inr)))
		return -EACCES;
	if ((S_ISDIR(inode->i_mode) && (flag & O_ACCMODE)) ||
	    permission(inode,ACC_MODE(flag))!=ACC_MODE(flag)) {
		iput(inode);
		return -EPERM;
	}
	inode->i_atime = CURRENT_TIME;
	if (flag & O_TRUNC)
		truncate(inode);
	*res_inode = inode;
	return 0;
}
\end{lstlisting}
\section{sys\_mkdir函数}
\paragraph{1} super\_block数组，最多支持8个，对应8个文件系统；
\begin{lstlisting}[breaklines]
int sys_mkdir(const char * pathname, int mode)
{
	const char * basename;
	int namelen;
	struct m_inode * dir, * inode;
	struct buffer_head * bh, *dir_block;
	struct dir_entry * de;

	if (current->euid && current->uid)
		return -EPERM;
	if (!(dir = dir_namei(pathname,&namelen,&basename)))
		return -ENOENT;
	if (!namelen) {
		iput(dir);
		return -ENOENT;
	}
	if (!permission(dir,MAY_WRITE)) {
		iput(dir);
		return -EPERM;
	}
	bh = find_entry(dir,basename,namelen,&de);
	if (bh) {
		brelse(bh);
		iput(dir);
		return -EEXIST;
	}
	inode = new_inode(dir->i_dev);
	if (!inode) {
		iput(dir);
		return -ENOSPC;
	}
	inode->i_size = 32;
	inode->i_dirt = 1;
	inode->i_mtime = inode->i_atime = CURRENT_TIME;
	if (!(inode->i_zone[0]=new_block(inode->i_dev))) {
		iput(dir);
		inode->i_nlinks--;
		iput(inode);
		return -ENOSPC;
	}
	inode->i_dirt = 1;
	if (!(dir_block=bread(inode->i_dev,inode->i_zone[0]))) {
		iput(dir);
		free_block(inode->i_dev,inode->i_zone[0]);
		inode->i_nlinks--;
		iput(inode);
		return -ERROR;
	}
	de = (struct dir_entry *) dir_block->b_data;
	de->inode=inode->i_num;
	strcpy(de->name,".");
	de++;
	de->inode = dir->i_num;
	strcpy(de->name,"..");
	inode->i_nlinks = 2;
	dir_block->b_dirt = 1;
	brelse(dir_block);
	inode->i_mode = I_DIRECTORY | (mode & 0777 & ~current->umask);
	inode->i_dirt = 1;
	bh = add_entry(dir,basename,namelen,&de);
	if (!bh) {
		iput(dir);
		free_block(inode->i_dev,inode->i_zone[0]);
		inode->i_nlinks=0;
		iput(inode);
		return -ENOSPC;
	}
	de->inode = inode->i_num;
	bh->b_dirt = 1;
	dir->i_nlinks++;
	dir->i_dirt = 1;
	iput(dir);
	iput(inode);
	brelse(bh);
	return 0;
}

/*
 * routine to check that the specified directory is empty (for rmdir)
 */
static int empty_dir(struct m_inode * inode)
{
	int nr,block;
	int len;
	struct buffer_head * bh;
	struct dir_entry * de;

	len = inode->i_size / sizeof (struct dir_entry);
	if (len<2 || !inode->i_zone[0] ||
	    !(bh=bread(inode->i_dev,inode->i_zone[0]))) {
	    	printk("warning - bad directory on dev %04x\n",inode->i_dev);
		return 0;
	}
	de = (struct dir_entry *) bh->b_data;
	if (de[0].inode != inode->i_num || !de[1].inode || 
	    strcmp(".",de[0].name) || strcmp("..",de[1].name)) {
	    	printk("warning - bad directory on dev %04x\n",inode->i_dev);
		return 0;
	}
	nr = 2;
	de += 2;
	while (nr<len) {
		if ((void *) de >= (void *) (bh->b_data+BLOCK_SIZE)) {
			brelse(bh);
			block=bmap(inode,nr/DIR_ENTRIES_PER_BLOCK);
			if (!block) {
				nr += DIR_ENTRIES_PER_BLOCK;
				continue;
			}
			if (!(bh=bread(inode->i_dev,block)))
				return 0;
			de = (struct dir_entry *) bh->b_data;
		}
		if (de->inode) {
			brelse(bh);
			return 0;
		}
		de++;
		nr++;
	}
	brelse(bh);
	return 1;
}

int sys_rmdir(const char * name)
{
	const char * basename;
	int namelen;
	struct m_inode * dir, * inode;
	struct buffer_head * bh;
	struct dir_entry * de;

	if (current->euid && current->uid)
		return -EPERM;
	if (!(dir = dir_namei(name,&namelen,&basename)))
		return -ENOENT;
	if (!namelen) {
		iput(dir);
		return -ENOENT;
	}
	bh = find_entry(dir,basename,namelen,&de);
	if (!bh) {
		iput(dir);
		return -ENOENT;
	}
	if (!permission(dir,MAY_WRITE)) {
		iput(dir);
		brelse(bh);
		return -EPERM;
	}
	if (!(inode = iget(dir->i_dev, de->inode))) {
		iput(dir);
		brelse(bh);
		return -EPERM;
	}
	if (inode == dir) {	/* we may not delete ".", but "../dir" is ok */
		iput(inode);
		iput(dir);
		brelse(bh);
		return -EPERM;
	}
	if (!S_ISDIR(inode->i_mode)) {
		iput(inode);
		iput(dir);
		brelse(bh);
		return -ENOTDIR;
	}
	if (!empty_dir(inode)) {
		iput(inode);
		iput(dir);
		brelse(bh);
		return -ENOTEMPTY;
	}
	if (inode->i_nlinks != 2)
		printk("empty directory has nlink!=2 (%d)",inode->i_nlinks);
	de->inode = 0;
	bh->b_dirt = 1;
	brelse(bh);
	inode->i_nlinks=0;
	inode->i_dirt=1;
	dir->i_nlinks--;
	dir->i_ctime = dir->i_mtime = CURRENT_TIME;
	dir->i_dirt=1;
	iput(dir);
	iput(inode);
	return 0;
}

int sys_unlink(const char * name)
{
	const char * basename;
	int namelen;
	struct m_inode * dir, * inode;
	struct buffer_head * bh;
	struct dir_entry * de;

	if (!(dir = dir_namei(name,&namelen,&basename)))
		return -ENOENT;
	if (!namelen) {
		iput(dir);
		return -ENOENT;
	}
	if (!permission(dir,MAY_WRITE)) {
		iput(dir);
		return -EPERM;
	}
	bh = find_entry(dir,basename,namelen,&de);
	if (!bh) {
		iput(dir);
		return -ENOENT;
	}
	inode = iget(dir->i_dev, de->inode);
	if (!inode) {
		printk("iget failed in delete (%04x:%d)",dir->i_dev,de->inode);
		iput(dir);
		brelse(bh);
		return -ENOENT;
	}
	if (!S_ISREG(inode->i_mode)) {
		iput(inode);
		iput(dir);
		brelse(bh);
		return -EPERM;
	}
	if (!inode->i_nlinks) {
		printk("Deleting nonexistent file (%04x:%d), %d\n",
			inode->i_dev,inode->i_num,inode->i_nlinks);
		inode->i_nlinks=1;
	}
	de->inode = 0;
	bh->b_dirt = 1;
	brelse(bh);
	inode->i_nlinks--;
	inode->i_dirt = 1;
	inode->i_ctime = CURRENT_TIME;
	iput(inode);
	iput(dir);
	return 0;
}

int sys_link(const char * oldname, const char * newname)
{
	struct dir_entry * de;
	struct m_inode * oldinode, * dir;
	struct buffer_head * bh;
	const char * basename;
	int namelen;

	oldinode=namei(oldname);
	if (!oldinode)
		return -ENOENT;
	if (!S_ISREG(oldinode->i_mode)) {
		iput(oldinode);
		return -EPERM;
	}
	dir = dir_namei(newname,&namelen,&basename);
	if (!dir) {
		iput(oldinode);
		return -EACCES;
	}
	if (!namelen) {
		iput(oldinode);
		iput(dir);
		return -EPERM;
	}
	if (dir->i_dev != oldinode->i_dev) {
		iput(dir);
		iput(oldinode);
		return -EXDEV;
	}
	if (!permission(dir,MAY_WRITE)) {
		iput(dir);
		iput(oldinode);
		return -EACCES;
	}
	bh = find_entry(dir,basename,namelen,&de);
	if (bh) {
		brelse(bh);
		iput(dir);
		iput(oldinode);
		return -EEXIST;
	}
	bh = add_entry(dir,basename,namelen,&de);
	if (!bh) {
		iput(dir);
		iput(oldinode);
		return -ENOSPC;
	}
	de->inode = oldinode->i_num;
	bh->b_dirt = 1;
	brelse(bh);
	iput(dir);
	oldinode->i_nlinks++;
	oldinode->i_ctime = CURRENT_TIME;
	oldinode->i_dirt = 1;
	iput(oldinode);
	return 0;
}
\end{lstlisting}
\chapter{文件操作源码fs/ftncl.c}
\section{全局变量}
\begin{lstlisting}[breaklines]
#include <string.h>
#include <errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <asm/segment.h>

#include <fcntl.h>
#include <sys/stat.h>

extern int sys_close(int fd);
\end{lstlisting}
\section{dupfd函数}
\paragraph{1} 从arg开始，找到当前任务中一个空闲的文件句柄；
\paragraph{2} 复制文件句柄，并将对应的文件引用次数+1；
\begin{lstlisting}[breaklines]
static int dupfd(unsigned int fd, unsigned int arg)
{
	if (fd >= NR_OPEN || !current->filp[fd])
		return -EBADF;
	if (arg >= NR_OPEN)
		return -EINVAL;
	while (arg < NR_OPEN)
		if (current->filp[arg])
			arg++;
		else
			break;
	if (arg >= NR_OPEN)
		return -EMFILE;
	current->close_on_exec &= ~(1<<arg);
	(current->filp[arg] = current->filp[fd])->f_count++;
	return arg;
}
\end{lstlisting}
\section{sys\_dup2函数}
\paragraph{1} super\_block数组，最多支持8个，对应8个文件系统；
\begin{lstlisting}[breaklines]
int sys_dup2(unsigned int oldfd, unsigned int newfd)
{
	sys_close(newfd);
	return dupfd(oldfd,newfd);
}
\end{lstlisting}
\section{sys\_dup函数}
\paragraph{1} 调用文件句柄复制函数，从最小可用句柄开始找一个空闲的复制；
\begin{lstlisting}[breaklines]
int sys_dup(unsigned int fildes)
{
	return dupfd(fildes,0);
}
\end{lstlisting}
\section{sys\_fcntl函数}
\paragraph{1} super\_block数组，最多支持8个，对应8个文件系统；
\begin{lstlisting}[breaklines]
int sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
{	
	struct file * filp;

	if (fd >= NR_OPEN || !(filp = current->filp[fd]))
		return -EBADF;
	switch (cmd) {
		case F_DUPFD:
			return dupfd(fd,arg);
		case F_GETFD:
			return (current->close_on_exec>>fd)&1;
		case F_SETFD:
			if (arg&1)
				current->close_on_exec |= (1<<fd);
			else
				current->close_on_exec &= ~(1<<fd);
			return 0;
		case F_GETFL:
			return filp->f_flags;
		case F_SETFL:
			filp->f_flags &= ~(O_APPEND | O_NONBLOCK);
			filp->f_flags |= arg & (O_APPEND | O_NONBLOCK);
			return 0;
		case F_GETLK:	case F_SETLK:	case F_SETLKW:
			return -1;
		default:
			return -1;
	}
}
\end{lstlisting}
\chapter{inode处理源码fs/inode.c}
\section{主要全局变量}
\begin{lstlisting}[breaklines]
#include <string.h>

#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <asm/system.h>

struct m_inode inode_table[NR_INODE]={{0,},};

static void read_inode(struct m_inode * inode);
static void write_inode(struct m_inode * inode);

static inline void wait_on_inode(struct m_inode * inode)
{
	cli();
	while (inode->i_lock)
		sleep_on(&inode->i_wait);
	sti();
}

static inline void lock_inode(struct m_inode * inode)
{
	cli();
	while (inode->i_lock)
		sleep_on(&inode->i_wait);
	inode->i_lock=1;
	sti();
}

static inline void unlock_inode(struct m_inode * inode)
{
	inode->i_lock=0;
	wake_up(&inode->i_wait);
}

void sync_inodes(void)
{
	int i;
	struct m_inode * inode;

	inode = 0+inode_table;
	for(i=0 ; i<NR_INODE ; i++,inode++) {
		wait_on_inode(inode);
		if (inode->i_dirt && !inode->i_pipe)
			write_inode(inode);
	}
}

static int _bmap(struct m_inode * inode,int block,int create)
{
	struct buffer_head * bh;
	int i;

	if (block<0)
		panic("_bmap: block<0");
	if (block >= 7+512+512*512)
		panic("_bmap: block>big");
	if (block<7) {
		if (create && !inode->i_zone[block])
			if (inode->i_zone[block]=new_block(inode->i_dev)) {
				inode->i_ctime=CURRENT_TIME;
				inode->i_dirt=1;
			}
		return inode->i_zone[block];
	}
	block -= 7;
	if (block<512) {
		if (create && !inode->i_zone[7])
			if (inode->i_zone[7]=new_block(inode->i_dev)) {
				inode->i_dirt=1;
				inode->i_ctime=CURRENT_TIME;
			}
		if (!inode->i_zone[7])
			return 0;
		if (!(bh = bread(inode->i_dev,inode->i_zone[7])))
			return 0;
		i = ((unsigned short *) (bh->b_data))[block];
		if (create && !i)
			if (i=new_block(inode->i_dev)) {
				((unsigned short *) (bh->b_data))[block]=i;
				bh->b_dirt=1;
			}
		brelse(bh);
		return i;
	}
	block -= 512;
	if (create && !inode->i_zone[8])
		if (inode->i_zone[8]=new_block(inode->i_dev)) {
			inode->i_dirt=1;
			inode->i_ctime=CURRENT_TIME;
		}
	if (!inode->i_zone[8])
		return 0;
	if (!(bh=bread(inode->i_dev,inode->i_zone[8])))
		return 0;
	i = ((unsigned short *)bh->b_data)[block>>9];
	if (create && !i)
		if (i=new_block(inode->i_dev)) {
			((unsigned short *) (bh->b_data))[block>>9]=i;
			bh->b_dirt=1;
		}
	brelse(bh);
	if (!i)
		return 0;
	if (!(bh=bread(inode->i_dev,i)))
		return 0;
	i = ((unsigned short *)bh->b_data)[block&511];
	if (create && !i)
		if (i=new_block(inode->i_dev)) {
			((unsigned short *) (bh->b_data))[block&511]=i;
			bh->b_dirt=1;
		}
	brelse(bh);
	return i;
}

int bmap(struct m_inode * inode,int block)
{
	return _bmap(inode,block,0);
}

int create_block(struct m_inode * inode, int block)
{
	return _bmap(inode,block,1);
}
\end{lstlisting}
\section{iput函数}
\paragraph{1} super\_block数组，最多支持8个，对应8个文件系统；
\begin{lstlisting}[breaklines]		
void iput(struct m_inode * inode)
{
	if (!inode)
		return;
	wait_on_inode(inode);
	if (!inode->i_count)
		panic("iput: trying to free free inode");
	if (inode->i_pipe) {
		wake_up(&inode->i_wait);
		if (--inode->i_count)
			return;
		free_page(inode->i_size);
		inode->i_count=0;
		inode->i_dirt=0;
		inode->i_pipe=0;
		return;
	}
	if (!inode->i_dev || inode->i_count>1) {
		inode->i_count--;
		return;
	}
repeat:
	if (!inode->i_nlinks) {
		truncate(inode);
		free_inode(inode);
		return;
	}
	if (inode->i_dirt) {
		write_inode(inode);	/* we can sleep - so do again */
		wait_on_inode(inode);
		goto repeat;
	}
	inode->i_count--;
	return;
}

static volatile int last_allocated_inode = 0;

struct m_inode * get_empty_inode(void)
{
	struct m_inode * inode;
	int inr;

	while (1) {
		inode = NULL;
		inr = last_allocated_inode;
		do {
			if (!inode_table[inr].i_count) {
				inode = inr + inode_table;
				break;
			}
			inr++;
			if (inr>=NR_INODE)
				inr=0;
		} while (inr != last_allocated_inode);
		if (!inode) {
			for (inr=0 ; inr<NR_INODE ; inr++)
				printk("%04x: %6d\t",inode_table[inr].i_dev,
					inode_table[inr].i_num);
			panic("No free inodes in mem");
		}
		last_allocated_inode = inr;
		wait_on_inode(inode);
		while (inode->i_dirt) {
			write_inode(inode);
			wait_on_inode(inode);
		}
		if (!inode->i_count)
			break;
	}
	memset(inode,0,sizeof(*inode));
	inode->i_count = 1;
	return inode;
}

struct m_inode * get_pipe_inode(void)
{
	struct m_inode * inode;

	if (!(inode = get_empty_inode()))
		return NULL;
	if (!(inode->i_size=get_free_page())) {
		inode->i_count = 0;
		return NULL;
	}
	inode->i_count = 2;	/* sum of readers/writers */
	PIPE_HEAD(*inode) = PIPE_TAIL(*inode) = 0;
	inode->i_pipe = 1;
	return inode;
}
\end{lstlisting}
\section{iget函数}
\paragraph{1} super\_block数组，最多支持8个，对应8个文件系统；
\begin{lstlisting}[breaklines]		
struct m_inode * iget(int dev,int nr)
{
	struct m_inode * inode, * empty;

	if (!dev)
		panic("iget with dev==0");
	empty = get_empty_inode();
	inode = inode_table;
	while (inode < NR_INODE+inode_table) {
		if (inode->i_dev != dev || inode->i_num != nr) {
			inode++;
			continue;
		}
		wait_on_inode(inode);
		if (inode->i_dev != dev || inode->i_num != nr) {
			inode = inode_table;
			continue;
		}
		inode->i_count++;
		if (empty)
			iput(empty);
		return inode;
	}
	if (!empty)
		return (NULL);
	inode=empty;
	inode->i_dev = dev;
	inode->i_num = nr;
	read_inode(inode);
	return inode;
}

static void read_inode(struct m_inode * inode)
{
	struct super_block * sb;
	struct buffer_head * bh;
	int block;

	lock_inode(inode);
	sb=get_super(inode->i_dev);
	block = 2 + sb->s_imap_blocks + sb->s_zmap_blocks +
		(inode->i_num-1)/INODES_PER_BLOCK;
	if (!(bh=bread(inode->i_dev,block)))
		panic("unable to read i-node block");
	*(struct d_inode *)inode =
		((struct d_inode *)bh->b_data)
			[(inode->i_num-1)%INODES_PER_BLOCK];
	brelse(bh);
	unlock_inode(inode);
}

static void write_inode(struct m_inode * inode)
{
	struct super_block * sb;
	struct buffer_head * bh;
	int block;

	lock_inode(inode);
	sb=get_super(inode->i_dev);
	block = 2 + sb->s_imap_blocks + sb->s_zmap_blocks +
		(inode->i_num-1)/INODES_PER_BLOCK;
	if (!(bh=bread(inode->i_dev,block)))
		panic("unable to read i-node block");
	((struct d_inode *)bh->b_data)
		[(inode->i_num-1)%INODES_PER_BLOCK] =
			*(struct d_inode *)inode;
	bh->b_dirt=1;
	inode->i_dirt=0;
	brelse(bh);
	unlock_inode(inode);
}
\end{lstlisting}
\chapter{读写处理源码fs/read\_write.c}
\section{全局变量}
\paragraph{1} super\_block数组，最多支持8个，对应8个文件系统；
\begin{lstlisting}[breaklines]
#include <sys/stat.h>
#include <errno.h>
#include <sys/types.h>

#include <linux/kernel.h>
#include <linux/sched.h>
#include <asm/segment.h>

extern int rw_char(int rw,int dev, char * buf, int count);
extern int read_pipe(struct m_inode * inode, char * buf, int count);
extern int write_pipe(struct m_inode * inode, char * buf, int count);
extern int block_read(int dev, off_t * pos, char * buf, int count);
extern int block_write(int dev, off_t * pos, char * buf, int count);
extern int file_read(struct m_inode * inode, struct file * filp,
		char * buf, int count);
extern int file_write(struct m_inode * inode, struct file * filp,
		char * buf, int count);

int sys_lseek(unsigned int fd,off_t offset, int origin)
{
	struct file * file;
	int tmp;

	if (fd >= NR_OPEN || !(file=current->filp[fd]) || !(file->f_inode)
	   || !IS_BLOCKDEV(MAJOR(file->f_inode->i_dev)))
		return -EBADF;
	if (file->f_inode->i_pipe)
		return -ESPIPE;
	switch (origin) {
		case 0:
			if (offset<0) return -EINVAL;
			file->f_pos=offset;
			break;
		case 1:
			if (file->f_pos+offset<0) return -EINVAL;
			file->f_pos += offset;
			break;
		case 2:
			if ((tmp=file->f_inode->i_size+offset) < 0)
				return -EINVAL;
			file->f_pos = tmp;
			break;
		default:
			return -EINVAL;
	}
	return file->f_pos;
}

int sys_read(unsigned int fd,char * buf,int count)
{
	struct file * file;
	struct m_inode * inode;

	if (fd>=NR_OPEN || count<0 || !(file=current->filp[fd]))
		return -EINVAL;
	if (!count)
		return 0;
	verify_area(buf,count);
	inode = file->f_inode;
	if (inode->i_pipe)
		return (file->f_mode&1)?read_pipe(inode,buf,count):-1;
	if (S_ISCHR(inode->i_mode))
		return rw_char(READ,inode->i_zone[0],buf,count);
	if (S_ISBLK(inode->i_mode))
		return block_read(inode->i_zone[0],&file->f_pos,buf,count);
	if (S_ISDIR(inode->i_mode) || S_ISREG(inode->i_mode)) {
		if (count+file->f_pos > inode->i_size)
			count = inode->i_size - file->f_pos;
		if (count<=0)
			return 0;
		return file_read(inode,file,buf,count);
	}
	printk("(Read)inode->i_mode=%06o\n\r",inode->i_mode);
	return -EINVAL;
}
\end{lstlisting}
\section{sys\_write函数}
\paragraph{1} 根据inode的类型调用对应的write函数；
\begin{lstlisting}[breaklines]
int sys_write(unsigned int fd,char * buf,int count)
{
	struct file * file;
	struct m_inode * inode;
	
	if (fd>=NR_OPEN || count <0 || !(file=current->filp[fd]))
		return -EINVAL;
	if (!count)
		return 0;
	inode=file->f_inode;
	if (inode->i_pipe)
		return (file->f_mode&2)?write_pipe(inode,buf,count):-1;
	if (S_ISCHR(inode->i_mode))
		return rw_char(WRITE,inode->i_zone[0],buf,count);
	if (S_ISBLK(inode->i_mode))
		return block_write(inode->i_zone[0],&file->f_pos,buf,count);
	if (S_ISREG(inode->i_mode))
		return file_write(inode,file,buf,count);
	printk("(Write)inode->i_mode=%06o\n\r",inode->i_mode);
	return -EINVAL;
}
\end{lstlisting}
\chapter{字符设备驱动程序源码fs/char\_dev.c}
\section{全局变量}
\paragraph{1} super\_block数组，最多支持8个，对应8个文件系统；
\begin{lstlisting}[breaklines]
#include <errno.h>

#include <linux/sched.h>
#include <linux/kernel.h>

extern int tty_read(unsigned minor,char * buf,int count);
extern int tty_write(unsigned minor,char * buf,int count);

static int rw_ttyx(int rw,unsigned minor,char * buf,int count);
static int rw_tty(int rw,unsigned minor,char * buf,int count);

typedef (*crw_ptr)(int rw,unsigned minor,char * buf,int count);

#define NRDEVS ((sizeof (crw_table))/(sizeof (crw_ptr)))

static crw_ptr crw_table[]={
	NULL,		/* nodev */
	NULL,		/* /dev/mem */
	NULL,		/* /dev/fd */
	NULL,		/* /dev/hd */
	rw_ttyx,	/* /dev/ttyx */
	rw_tty,		/* /dev/tty */
	NULL,		/* /dev/lp */
	NULL};		/* unnamed pipes */
\end{lstlisting}
\section{rw\_ttyx函数}
\paragraph{1} 调用tty对应的字符读写函数；
\begin{lstlisting}[breaklines]
static int rw_ttyx(int rw,unsigned minor,char * buf,int count)
{
	return ((rw==READ)?tty_read(minor,buf,count):
		tty_write(minor,buf,count));
}
\end{lstlisting}
\section{rw\_tty函数}
\paragraph{1} 如果当前进程的tty存在，调用对应的字符读写函数；
\begin{lstlisting}[breaklines]
static int rw_tty(int rw,unsigned minor,char * buf,int count)
{
	if (current->tty<0)
		return -EPERM;
	return rw_ttyx(rw,current->tty,buf,count);
}
\end{lstlisting}
\section{rw\_char函数}
\paragraph{1} 根据crw\_table表的配置调用对应的字符读写函数；
\begin{lstlisting}[breaklines]
int rw_char(int rw,int dev, char * buf, int count)
{
	crw_ptr call_addr;

	if (MAJOR(dev)>=NRDEVS)
		panic("rw_char: dev>NRDEV");
	if (!(call_addr=crw_table[MAJOR(dev)])) {
		printk("dev: %04x\n",dev);
		panic("Trying to r/w from/to nonexistent character device");
	}
	return call_addr(rw,MINOR(dev),buf,count);
}
\end{lstlisting}

\chapter{工程文件}
\chapter{模拟运行}
\section{准备硬盘映像文件}
\subsection{硬盘参数}
在include/linux/config.h文件中，我们可以看到对硬盘参数的定义，我们看到在定义了 LINUS\_HD 宏的情况下，我们需要两个参数相同的硬盘，硬盘参数是（5,17,980,300,980,0）
\begin{lstlisting}[breaklines]
#if	defined(LASU_HD)
#define HD_TYPE { 7,35,915,65536,920,0 }
#elif	defined(LINUS_HD)
#define HD_TYPE { 5,17,980,300,980,0 },{ 5,17,980,300,980,0 }
\end{lstlisting}
在kernel/hd.c文件中，我们可以看到几个硬盘参数分别对应含义
\begin{lstlisting}[breaklines]
static struct hd_i_struct{
	int head,sect,cyl,wpcom,lzone,ctl;
	} hd_info[]= { HD_TYPE };
\end{lstlisting}
即，head = 5, sect = 17， cyl = 980，5个磁头，980个柱面，每个柱面17个扇区。
\subsection{生成硬盘映像}
根据硬盘参数，我们可以计算得到硬盘的扇区数： 5 * 17 * 980 = 83300
\begin{lstlisting}[breaklines]
dd if=/dev/zero of=hdc.img bs=512 count=83300
\end{lstlisting}
\subsection{格式化硬盘映像}
我们使用fdisk命令格式化硬盘，其中-c=dos -u=cylinders指示fdisk使用dos兼容模式，并使用cylinders作为单位。
\begin{lstlisting}[breaklines]
fdisk -c=dos -u=cylinders hdc.img
`欢迎使用 fdisk (util-linux 2.34)。`
`更改将停留在内存中，直到您决定将更改写入磁盘。`
`使用写入命令前请三思。`

`设备不包含可识别的分区表。`
`DOS 兼容模式已废弃。`
`以柱面为显示单位的方式已废弃。`

`创建了一个磁盘标识符为 0x27efac31 的新 DOS 磁盘标签。`

`命令(输入 m 获取帮助)： `
\end{lstlisting}
我们要设置硬盘的head、sect、cyl参数，需要进入专家模式，键入'x'
\begin{lstlisting}[breaklines]
`命令(输入 m 获取帮助)： x`

`专家命令(输入 m 显示帮助)： c`
`柱面数 (1-1048576, 默认 5): 980`

`专家命令(输入 m 显示帮助)： h`
`磁头数 (1-255, 默认 255): 5`

`专家命令(输入 m 显示帮助)： s`
`扇区数 (1-63, 默认 63): 17`

`专家命令(输入 m 显示帮助)： r`
\end{lstlisting}
接下来创建一个主分区
\begin{lstlisting}[breaklines]
`命令(输入 m 获取帮助)： n`
`分区类型`
`   p   主分区 (0个主分区，0个扩展分区，4空闲)`
`   e   扩展分区 (逻辑分区容器)`
`选择 (默认 p)： p`
`分区号 (1-4, 默认  1): `
`第一个柱面 (1-980, 默认 1): `
`Last cylinder, +/-cylinders or +/-size{K,M,G,T,P} (1-980, 默认 980): `

`创建了一个新分区 1，类型为“Linux”，大小为 40.7 MiB。`
\end{lstlisting}
修改分区类型，并保存退出
\begin{lstlisting}[breaklines]
`命令(输入 m 获取帮助)： t`
`已选择分区 1`
`Hex 代码(输入 L 列出所有代码)： 0x81`
`已将分区“Linux”的类型更改为“Minix / old Linux”。`
`命令(输入 m 获取帮助)： w`
`分区表已调整。`
`正在同步磁盘。`
\end{lstlisting}
\subsection{安装文件系统}
ubuntu不再支持Minix / old Linux文件系统，我们不能安装文件系统。
\subsection{修改Bochs资源文件}
前面提到定义了LINUS\_HD 宏的情况下，我们需要两个参数相同的硬盘。
\begin{lstlisting}[breaklines]
ata0-master: type=disk, path=./B4M, cylinders=980, heads=5, spt=17, translation=none
ata0-slave: type=disk, path=./C4M, cylinders=980, heads=5, spt=17, translation=none
\end{lstlisting}
\section{修改硬盘映像文件}
\subsection{分区表信息}
\subsection{super}
\subsection{inode1}
\subsection{inode2}
\subsection{inode3}
\subsection{inode4}
\subsection{从页表之后找到main函数的入口地址}
\paragraph{1} 0x0008:0x518c，即main函数的入口地址
\begin{lstlisting}[breaklines]
      82:	75 f5                	jne    0x79
      84:	0f 01 1d 6a 40 00 00 	lidtl  0x406a
      8b:	c3                   	ret    
      8c:	0f 01 15 72 40 00 00 	lgdtl  0x4072
      93:	c3                   	ret    
	...
    4000:	6a 00                	push   $0x0
    4002:	6a 00                	push   $0x0
    4004:	6a 00                	push   $0x0
    4006:	68 12 40 00 00       	push   $0x4012
    400b:	68 8c 51 00 00       	push   $0x518c
    4010:	eb 12                	jmp    0x4024
    4012:	eb fe                	jmp    0x4012
    4014:	fe 05 a0 80 0b 00    	incb   0xb80a0
    401a:	c6 05 a1 80 0b 00 02 	movb   $0x2,0xb80a1
    4021:	cf                   	iret   
\end{lstlisting}
\subsection{main函数的反汇编及其调用的函数入口地址}
\begin{lstlisting}[breaklines]
    518c:	f3 0f 1e fb          	endbr32 
    5190:	55                   	push   %ebp
    5191:	89 e5                	mov    %esp,%ebp
    5193:	53                   	push   %ebx
    5194:	83 e4 f0             	and    $0xfffffff0,%esp
    5197:	e8 5c 00 00 00       	call   0x51f8
    519c:	81 c3 64 1e 01 00    	add    $0x11e64,%ebx
    51a2:	e8 3e 13 00 00       	call   0x64e5    (tty_init)
    51a7:	e8 8f 29 00 00       	call   0x7b3b    (trap_init)
    51ac:	e8 74 04 00 00       	call   0x5625    (sched_init)
    51b1:	e8 0a 67 00 00       	call   0xb8c0    (buffer_init)
    51b6:	e8 e6 3f 00 00       	call   0x91a1    (hd_init)
    51bb:	fb                   	sti    
    51bc:	89 e0                	mov    %esp,%eax
    51be:	6a 17                	push   $0x17
    51c0:	50                   	push   %eax
    51c1:	9c                   	pushf  
    51c2:	6a 0f                	push   $0xf
    51c4:	68 ca 51 00 00       	push   $0x51ca
    51c9:	cf                   	iret   
    51ca:	b8 17 00 00 00       	mov    $0x17,%eax
    51cf:	8e d8                	mov    %eax,%ds
    51d1:	8e c0                	mov    %eax,%es
    51d3:	8e e0                	mov    %eax,%fs
    51d5:	8e e8                	mov    %eax,%gs
    51d7:	b8 02 00 00 00       	mov    $0x2,%eax
    51dc:	cd 80                	int    $0x80     (fork)
    51de:	85 c0                	test   %eax,%eax
    51e0:	74 0b                	je     0x51ed
    51e2:	ba 1d 00 00 00       	mov    $0x1d,%edx
    51e7:	89 d0                	mov    %edx,%eax
    51e9:	cd 80                	int    $0x80     (pause)     
    51eb:	eb fa                	jmp    0x51e7
    51ed:	e8 e6 fe ff ff       	call   0x50d8    (init)
    51f2:	eb ee                	jmp    0x51e2
    51f4:	8b 0c 24             	mov    (%esp),%ecx
    51f7:	c3                   	ret    
    51f8:	8b 1c 24             	mov    (%esp),%ebx
    51fb:	c3                   	ret    
\end{lstlisting} 
\subsection{sched\_init函数的反汇编及其调用的函数入口地址}
\begin{lstlisting}[breaklines]
    5625:	f3 0f 1e fb          	endbr32 
    5629:	56                   	push   %esi
    562a:	53                   	push   %ebx
    562b:	e8 c8 fb ff ff       	call   0x51f8
    5630:	81 c3 d0 19 01 00    	add    $0x119d0,%ebx
    5636:	8d 83 c0 01 00 00    	lea    0x1c0(%ebx),%eax
    563c:	c7 c1 78 48 00 00    	mov    $0x4878,%ecx
    5642:	66 c7 41 20 68 00    	movw   $0x68,0x20(%ecx)
    5648:	66 89 41 22          	mov    %ax,0x22(%ecx)
    564c:	c1 c8 10             	ror    $0x10,%eax
    564f:	88 41 24             	mov    %al,0x24(%ecx)
    5652:	c6 41 25 89          	movb   $0x89,0x25(%ecx)
    5656:	c6 41 26 00          	movb   $0x0,0x26(%ecx)
    565a:	88 61 27             	mov    %ah,0x27(%ecx)
    565d:	c1 c8 10             	ror    $0x10,%eax
    5660:	8d 40 e8             	lea    -0x18(%eax),%eax
    5663:	66 c7 41 28 68 00    	movw   $0x68,0x28(%ecx)
    5669:	66 89 41 2a          	mov    %ax,0x2a(%ecx)
    566d:	c1 c8 10             	ror    $0x10,%eax
    5670:	88 41 2c             	mov    %al,0x2c(%ecx)
    5673:	c6 41 2d 82          	movb   $0x82,0x2d(%ecx)
    5677:	c6 41 2e 00          	movb   $0x0,0x2e(%ecx)
    567b:	88 61 2f             	mov    %ah,0x2f(%ecx)
    567e:	c1 c8 10             	ror    $0x10,%eax
    5681:	8d 93 e4 1d 00 00    	lea    0x1de4(%ebx),%edx
    5687:	8d 41 30             	lea    0x30(%ecx),%eax
    568a:	8d 89 20 04 00 00    	lea    0x420(%ecx),%ecx
    5690:	c7 02 00 00 00 00    	movl   $0x0,(%edx)
    5696:	c7 40 04 00 00 00 00 	movl   $0x0,0x4(%eax)
    569d:	c7 00 00 00 00 00    	movl   $0x0,(%eax)
    56a3:	c7 40 0c 00 00 00 00 	movl   $0x0,0xc(%eax)
    56aa:	c7 40 08 00 00 00 00 	movl   $0x0,0x8(%eax)
    56b1:	83 c0 10             	add    $0x10,%eax
    56b4:	83 c2 04             	add    $0x4,%edx
    56b7:	39 c8                	cmp    %ecx,%eax
    56b9:	75 d5                	jne    0x5690
    56bb:	b8 20 00 00 00       	mov    $0x20,%eax
    56c0:	0f 00 d8             	ltr    %ax
    56c3:	b8 28 00 00 00       	mov    $0x28,%eax
    56c8:	0f 00 d0             	lldt   %ax
    56cb:	b8 36 00 00 00       	mov    $0x36,%eax
    56d0:	ba 43 00 00 00       	mov    $0x43,%edx
    56d5:	ee                   	out    %al,(%dx)
    56d6:	eb 00                	jmp    0x56d8
    56d8:	eb 00                	jmp    0x56da
    56da:	ba 40 00 00 00       	mov    $0x40,%edx
    56df:	b8 9b 00 00 00       	mov    $0x9b,%eax
    56e4:	ee                   	out    %al,(%dx)
    56e5:	eb 00                	jmp    0x56e7
    56e7:	eb 00                	jmp    0x56e9
    56e9:	b8 2e 00 00 00       	mov    $0x2e,%eax
    56ee:	ee                   	out    %al,(%dx)
    56ef:	c7 c1 78 40 00 00    	mov    $0x4078,%ecx
    56f5:	be 00 00 08 00       	mov    $0x80000,%esi
    56fa:	c7 c2 b8 6f 00 00    	mov    $0x6fb8,%edx (timer_interrupt)
    5700:	89 f0                	mov    %esi,%eax
    5702:	66 89 d0             	mov    %dx,%ax
    5705:	66 ba 00 8e          	mov    $0x8e00,%dx
    5709:	89 81 00 01 00 00    	mov    %eax,0x100(%ecx)
    570f:	89 91 04 01 00 00    	mov    %edx,0x104(%ecx)
    5715:	ba 21 00 00 00       	mov    $0x21,%edx
    571a:	ec                   	in     (%dx),%al
    571b:	eb 00                	jmp    0x571d
    571d:	eb 00                	jmp    0x571f
    571f:	25 fe 00 00 00       	and    $0xfe,%eax
    5724:	ee                   	out    %al,(%dx)
    5725:	c7 c2 d8 6e 00 00    	mov    $0x6ed8,%edx (system_call)
    572b:	89 f0                	mov    %esi,%eax
    572d:	66 89 d0             	mov    %dx,%ax
    5730:	66 ba 00 ef          	mov    $0xef00,%dx
    5734:	89 81 00 04 00 00    	mov    %eax,0x400(%ecx)
    573a:	89 91 04 04 00 00    	mov    %edx,0x404(%ecx)
    5740:	5b                   	pop    %ebx
    5741:	5e                   	pop    %esi
    5742:	c3                   	ret    
 \end{lstlisting} 

\paragraph{2} system\_call的反汇编结果：
\begin{lstlisting}[breaklines]
    6ed8:	83 f8 42             	cmp    $0x42,%eax
    6edb:	77 e7                	ja     0x6ec4
    6edd:	1e                   	push   %ds
    6ede:	06                   	push   %es
    6edf:	0f a0                	push   %fs
    6ee1:	52                   	push   %edx
    6ee2:	51                   	push   %ecx
    6ee3:	53                   	push   %ebx
    6ee4:	ba 10 00 00 00       	mov    $0x10,%edx
    6ee9:	8e da                	mov    %edx,%ds
    6eeb:	8e c2                	mov    %edx,%es
    6eed:	ba 17 00 00 00       	mov    $0x17,%edx
    6ef2:	8e e2                	mov    %edx,%fs
    6ef4:	ff 14 85 60 80 01 00 	call   *0x18060(,%eax,4) sys_call_table
\end{lstlisting}   
\subsection{sys\_call\_table反汇编内容}
\paragraph{0} 其中0x26900000，对应sys\_setup, 0x9026。
\paragraph{3} 其中0x00700000，对应sys\_fork, 0x7000。
\paragraph{29} 其中0x4c530000，对应sys\_pause, 0x534c。
\begin{lstlisting}[breaklines]
 18060 26900000 00000000 00700000 00000000  %........p......
 18070 18a30000 3a9c0000 00000000 00000000  ....:...........
 18080 00000000 00000000 00000000 00000000  ................
 18090 00000000 00000000 00000000 00000000  ................
 180a0 00000000 00000000 00000000 00000000  ................
 180b0 00000000 00000000 00000000 00000000  ................
 180c0 00000000 00000000 00000000 00000000  ................
 180d0 00000000 4c530000 00000000 00000000  ....LS..........
 180e0 00000000 00000000 00000000 00000000  ................
 180f0 00000000 00000000 00000000 00000000  ................
 18100 00000000 43020100 00000000 00000000  ....C...........
\end{lstlisting}   

\subsection{sys\_fork反汇编内容}
\paragraph{1} 其中0x00700000，对应sys\_fork, 0x7000。
\begin{lstlisting}[breaklines]
    7000:	e8 09 18 00 00       	call   0x880e
    7005:	85 c0                	test   %eax,%eax
    7007:	78 0e                	js     0x7017
    7009:	0f a8                	push   %gs
    700b:	56                   	push   %esi
    700c:	57                   	push   %edi
    700d:	55                   	push   %ebp
    700e:	50                   	push   %eax
    700f:	e8 5b 15 00 00       	call   0x856f      copy_process
    7014:	83 c4 14             	add    $0x14,%esp
    7017:	c3                   	ret    
\end{lstlisting}   
\subsection{sys\_pause反汇编内容}
\begin{lstlisting}[breaklines]
    534c:	f3 0f 1e fb          	endbr32 
    5350:	e8 f0 3e 00 00       	call   0x9245
    5355:	05 ab 1c 01 00       	add    $0x11cab,%eax
    535a:	8b 80 e0 1e 00 00    	mov    0x1ee0(%eax),%eax
    5360:	c7 00 01 00 00 00    	movl   $0x1,(%eax)
    5366:	e8 d9 fe ff ff       	call   0x5244      schedule
    536b:	b8 00 00 00 00       	mov    $0x0,%eax
    5370:	c3                   	ret  
\end{lstlisting}       
\subsection{schedule反汇编内容}
\begin{lstlisting}[breaklines]
    5244:	f3 0f 1e fb          	endbr32 
    5248:	55                   	push   %ebp
    5249:	57                   	push   %edi
    524a:	56                   	push   %esi
    524b:	53                   	push   %ebx
    524c:	83 ec 10             	sub    $0x10,%esp
    524f:	e8 a4 ff ff ff       	call   0x51f8
    5254:	81 c3 ac 1d 01 00    	add    $0x11dac,%ebx
    525a:	8d 83 dc 1e 00 00    	lea    0x1edc(%ebx),%eax
    5260:	8d b3 e0 1d 00 00    	lea    0x1de0(%ebx),%esi
    5266:	eb 14                	jmp    0x527c
    5268:	8b 10                	mov    (%eax),%edx
    526a:	83 7a 0c 00          	cmpl   $0x0,0xc(%edx)
    526e:	74 05                	je     0x5275
    5270:	83 3a 01             	cmpl   $0x1,(%edx)
    5273:	74 36                	je     0x52ab
    5275:	83 e8 04             	sub    $0x4,%eax
    5278:	39 f0                	cmp    %esi,%eax
    527a:	74 37                	je     0x52b3
    527c:	8b 10                	mov    (%eax),%edx
    527e:	85 d2                	test   %edx,%edx
    5280:	74 f3                	je     0x5275
    5282:	8b 8a c8 00 00 00    	mov    0xc8(%edx),%ecx
    5288:	85 c9                	test   %ecx,%ecx
    528a:	74 dc                	je     0x5268
    528c:	8b bb 88 24 00 00    	mov    0x2488(%ebx),%edi
    5292:	39 f9                	cmp    %edi,%ecx
    5294:	7d d2                	jge    0x5268
    5296:	81 4a 0c 00 20 00 00 	orl    $0x2000,0xc(%edx)
    529d:	8b 10                	mov    (%eax),%edx
    529f:	c7 82 c8 00 00 00 00 	movl   $0x0,0xc8(%edx)
    52a6:	00 00 00 
    52a9:	eb bd                	jmp    0x5268
    52ab:	c7 02 00 00 00 00    	movl   $0x0,(%edx)
    52b1:	eb c2                	jmp    0x5275
    52b3:	be ff ff ff ff       	mov    $0xffffffff,%esi
    52b8:	8d 8b e0 1d 00 00    	lea    0x1de0(%ebx),%ecx
    52be:	b8 3f 00 00 00       	mov    $0x3f,%eax
    52c3:	89 f7                	mov    %esi,%edi
    52c5:	bd 00 00 00 00       	mov    $0x0,%ebp
    52ca:	eb 05                	jmp    0x52d1
    52cc:	83 e8 01             	sub    $0x1,%eax
    52cf:	74 1d                	je     0x52ee
    52d1:	8b 94 83 e0 1d 00 00 	mov    0x1de0(%ebx,%eax,4),%edx
    52d8:	85 d2                	test   %edx,%edx          (!*--p)
    52da:	74 f0                	je     0x52cc
    52dc:	83 3a 00             	cmpl   $0x0,(%edx)        (*p)->state != TASK_RUNNING
    52df:	75 eb                	jne    0x52cc
    52e1:	8b 52 04             	mov    0x4(%edx),%edx
    52e4:	39 fa                	cmp    %edi,%edx          (*p)->counter <= c)
    52e6:	7e e4                	jle    0x52cc
    52e8:	89 d7                	mov    %edx,%edi
    52ea:	89 c5                	mov    %eax,%ebp
    52ec:	eb de                	jmp    0x52cc
    52ee:	85 ff                	test   %edi,%edi
    52f0:	75 22                	jne    0x5314             if (c) break;
    52f2:	8d bb dc 1e 00 00    	lea    0x1edc(%ebx),%edi
    52f8:	eb 07                	jmp    0x5301
    52fa:	83 ef 04             	sub    $0x4,%edi
    52fd:	39 cf                	cmp    %ecx,%edi
    52ff:	74 bd                	je     0x52be
    5301:	8b 17                	mov    (%edi),%edx
    5303:	85 d2                	test   %edx,%edx
    5305:	74 f3                	je     0x52fa
    5307:	8b 42 04             	mov    0x4(%edx),%eax
    530a:	d1 f8                	sar    %eax
    530c:	03 42 08             	add    0x8(%edx),%eax
    530f:	89 42 04             	mov    %eax,0x4(%edx)
    5312:	eb e6                	jmp    0x52fa
    5314:	89 ea                	mov    %ebp,%edx  switch_to(next);
    5316:	c1 e2 04             	shl    $0x4,%edx
    5319:	83 c2 20             	add    $0x20,%edx
    531c:	8b 8c ab e0 1d 00 00 	mov    0x1de0(%ebx,%ebp,4),%ecx
    5323:	39 0d e0 8e 01 00    	cmp    %ecx,0x18ee0
    5329:	74 19                	je     0x5344
    532b:	87 0d e0 8e 01 00    	xchg   %ecx,0x18ee0
    5331:	66 89 54 24 0c       	mov    %dx,0xc(%esp)
    5336:	ff 6c 24 08          	ljmp   *0x8(%esp)
    533a:	39 8b 80 24 00 00    	cmp    %ecx,0x2480(%ebx)
    5340:	75 02                	jne    0x5344
    5342:	0f 06                	clts   
    5344:	83 c4 10             	add    $0x10,%esp
    5347:	5b                   	pop    %ebx
    5348:	5e                   	pop    %esi
    5349:	5f                   	pop    %edi
    534a:	5d                   	pop    %ebp
    534b:	c3                   	ret    
\end{lstlisting}

\begin{lstlisting}[breaklines]
0x0000000000018de0                task
<bochs:274> x /2 0x08:0x18de0
[bochs]:
0x00018de0 <bogus+       0>:	0x00017060	0x007ff000

x /141 0x08:0x17060
x /141 0x08:0x7ff000
x /141 0x10:0x7ff000
x /168 0x10:0x17060
x /168 0x10:0x7ff000

x /10 0x10:0x1800c
x /64 0x08:0x4878
0x00004878 <bogus+       0>:	0x00000000	0x00000000	0x000007ff	0x00c09b00
0x00004888 <bogus+      16>:	0x000007ff	0x00c09300	0x00000000	0x00000000
0x00004898 <bogus+      32>:	0x71c00068	0x00008901	0x71a80068	0x00008201
0x000048a8 <bogus+      48>:	0xf1600068	0x00008b7f	0xf1480068	0x0000827f
gdtr:base=0x00004878, limit=0x7ff
idtr:base=0x00004078, limit=0x7ff

eflags 0x00000606: id vip vif ac vm rf nt IOPL=0 of DF IF tf sf zf af PF cf
= 0b11000000110
\end{lstlisting}
\begin{lstlisting}[breaklines]
    8573:	55                   	push   %ebp
    8574:	57                   	push   %edi
    8575:	56                   	push   %esi
    8576:	53                   	push   %ebx
    8577:	83 ec 0c             	sub    $0xc,%esp
    857a:	e8 ce 0c 00 00       	call   0x924d
    857f:	81 c5 81 ea 00 00    	add    $0xea81,%ebp
    8585:	89 eb                	mov    %ebp,%ebx
    8587:	e8 cd 0c 00 00       	call   0x9259     get_free_page();
    858c:	89 c3                	mov    %eax,%ebx
    858e:	85 c0                	test   %eax,%eax
    8590:	0f 84 71 02 00 00    	je     0x8807
    8596:	c7 c2 e0 8e 01 00    	mov    $0x18ee0,%edx
    859c:	8b 32                	mov    (%edx),%esi
    859e:	b9 8d 00 00 00       	mov    $0x8d,%ecx
    85a3:	89 c7                	mov    %eax,%edi
    85a5:	f3 a5                	rep movsl %ds:(%esi),%es:(%edi)
    85a7:	c7 00 00 00 00 00    	movl   $0x0,(%eax)         state = TASK_RUNNING;
    85ad:	8b 85 20 29 00 00    	mov    0x2920(%ebp),%eax   
    85b3:	89 83 a8 00 00 00    	mov    %eax,0xa8(%ebx)     pid = last_pid
    85b9:	8b 12                	mov    (%edx),%edx
    85bb:	8b 82 a8 00 00 00    	mov    0xa8(%edx),%eax
    85c1:	89 83 ac 00 00 00    	mov    %eax,0xac(%ebx)     father = current->pid
    85c7:	8b 43 08             	mov    0x8(%ebx),%eax  
    85ca:	89 43 04             	mov    %eax,0x4(%ebx)      counter = priority
    85cd:	c7 43 0c 00 00 00 00 	movl   $0x0,0xc(%ebx)
    85d4:	c7 83 c8 00 00 00 00 	movl   $0x0,0xc8(%ebx)
    85db:	00 00 00 
    85de:	c7 83 b8 00 00 00 00 	movl   $0x0,0xb8(%ebx)
    85e5:	00 00 00 
    85e8:	c7 83 d0 00 00 00 00 	movl   $0x0,0xd0(%ebx)
    85ef:	00 00 00 
    85f2:	c7 83 cc 00 00 00 00 	movl   $0x0,0xcc(%ebx)
    85f9:	00 00 00 
    85fc:	c7 83 d8 00 00 00 00 	movl   $0x0,0xd8(%ebx)
    8603:	00 00 00 
    8606:	c7 83 d4 00 00 00 00 	movl   $0x0,0xd4(%ebx)
    860d:	00 00 00 
    8610:	c7 c0 88 94 01 00    	mov    $0x19488,%eax
    8616:	8b 00                	mov    (%eax),%eax
    8618:	89 83 dc 00 00 00    	mov    %eax,0xdc(%ebx)
    861e:	c7 83 60 01 00 00 00 	movl   $0x0,0x160(%ebx)
    8625:	00 00 00 
    8628:	8d 83 00 10 00 00    	lea    0x1000(%ebx),%eax
    862e:	89 83 64 01 00 00    	mov    %eax,0x164(%ebx)
    8634:	c7 83 68 01 00 00 10 	movl   $0x10,0x168(%ebx)
    863b:	00 00 00 
    863e:	8b 44 24 50          	mov    0x50(%esp),%eax
    8642:	89 83 80 01 00 00    	mov    %eax,0x180(%ebx)
    8648:	8b 44 24 58          	mov    0x58(%esp),%eax
    864c:	89 83 84 01 00 00    	mov    %eax,0x184(%ebx)
    8652:	c7 83 88 01 00 00 00 	movl   $0x0,0x188(%ebx)
    8659:	00 00 00 
    865c:	8b 44 24 3c          	mov    0x3c(%esp),%eax
    8660:	89 83 8c 01 00 00    	mov    %eax,0x18c(%ebx)
    8666:	8b 44 24 40          	mov    0x40(%esp),%eax
    866a:	89 83 90 01 00 00    	mov    %eax,0x190(%ebx)
    8670:	8b 44 24 38          	mov    0x38(%esp),%eax
    8674:	89 83 94 01 00 00    	mov    %eax,0x194(%ebx)
    867a:	8b 44 24 5c          	mov    0x5c(%esp),%eax
    867e:	89 83 98 01 00 00    	mov    %eax,0x198(%ebx)
    8684:	8b 44 24 24          	mov    0x24(%esp),%eax
    8688:	89 83 9c 01 00 00    	mov    %eax,0x19c(%ebx)
    868e:	8b 44 24 2c          	mov    0x2c(%esp),%eax
    8692:	89 83 a0 01 00 00    	mov    %eax,0x1a0(%ebx)
    8698:	8b 44 24 28          	mov    0x28(%esp),%eax
    869c:	89 83 a4 01 00 00    	mov    %eax,0x1a4(%ebx)
    86a2:	0f b7 44 24 48       	movzwl 0x48(%esp),%eax
    86a7:	89 83 a8 01 00 00    	mov    %eax,0x1a8(%ebx)
    86ad:	0f b7 44 24 54       	movzwl 0x54(%esp),%eax
    86b2:	89 83 ac 01 00 00    	mov    %eax,0x1ac(%ebx)
    86b8:	0f b7 44 24 60       	movzwl 0x60(%esp),%eax
    86bd:	89 83 b0 01 00 00    	mov    %eax,0x1b0(%ebx)
    86c3:	0f b7 44 24 4c       	movzwl 0x4c(%esp),%eax
    86c8:	89 83 b4 01 00 00    	mov    %eax,0x1b4(%ebx)
    86ce:	0f b7 44 24 44       	movzwl 0x44(%esp),%eax
    86d3:	89 83 b8 01 00 00    	mov    %eax,0x1b8(%ebx)
    86d9:	0f b7 44 24 30       	movzwl 0x30(%esp),%eax
    86de:	89 83 bc 01 00 00    	mov    %eax,0x1bc(%ebx)
    86e4:	8b 44 24 20          	mov    0x20(%esp),%eax
    86e8:	c1 e0 04             	shl    $0x4,%eax
    86eb:	83 c0 28             	add    $0x28,%eax
    86ee:	89 83 c0 01 00 00    	mov    %eax,0x1c0(%ebx)
    86f4:	c7 83 c4 01 00 00 00 	movl   $0x80000000,0x1c4(%ebx)
    86fb:	00 00 80 
    86fe:	c7 c0 80 94 01 00    	mov    $0x19480,%eax
    8704:	3b 10                	cmp    (%eax),%edx
    8706:	74 22                	je     0x872a
    8708:	83 ec 08             	sub    $0x8,%esp
    870b:	53                   	push   %ebx
    870c:	ff 74 24 2c          	pushl  0x2c(%esp)
    8710:	e8 5e fd ff ff       	call   0x8473
    8715:	83 c4 10             	add    $0x10,%esp
    8718:	85 c0                	test   %eax,%eax
    871a:	75 16                	jne    0x8732
    871c:	8d 83 f8 00 00 00    	lea    0xf8(%ebx),%eax
    8722:	8d 8b 48 01 00 00    	lea    0x148(%ebx),%ecx
    8728:	eb 27                	jmp    0x8751
    872a:	dd b3 c8 01 00 00    	fnsave 0x1c8(%ebx)
    8730:	eb d6                	jmp    0x8708
    8732:	83 ec 0c             	sub    $0xc,%esp
    8735:	53                   	push   %ebx
    8736:	89 eb                	mov    %ebp,%ebx
    8738:	e8 63 0b 00 00       	call   0x92a0
    873d:	83 c4 10             	add    $0x10,%esp
    8740:	b8 f5 ff ff ff       	mov    $0xfffffff5,%eax
    8745:	e9 b5 00 00 00       	jmp    0x87ff
    874a:	83 c0 04             	add    $0x4,%eax
    874d:	39 c8                	cmp    %ecx,%eax
    874f:	74 0d                	je     0x875e
    8751:	8b 10                	mov    (%eax),%edx
    8753:	85 d2                	test   %edx,%edx
    8755:	74 f3                	je     0x874a
    8757:	66 83 42 04 01       	addw   $0x1,0x4(%edx)
    875c:	eb ec                	jmp    0x874a
    875e:	c7 c0 e0 8e 01 00    	mov    $0x18ee0,%eax
    8764:	8b 10                	mov    (%eax),%edx
    8766:	8b 82 ec 00 00 00    	mov    0xec(%edx),%eax
    876c:	85 c0                	test   %eax,%eax
    876e:	74 05                	je     0x8775
    8770:	66 83 40 30 01       	addw   $0x1,0x30(%eax)
    8775:	8b 82 f0 00 00 00    	mov    0xf0(%edx),%eax
    877b:	85 c0                	test   %eax,%eax
    877d:	74 05                	je     0x8784
    877f:	66 83 40 30 01       	addw   $0x1,0x30(%eax)
    8784:	8b 44 24 20          	mov    0x20(%esp),%eax
    8788:	8d 74 00 04          	lea    0x4(%eax,%eax,1),%esi
    878c:	8d 0c f5 00 00 00 00 	lea    0x0(,%esi,8),%ecx
    8793:	8d 83 60 01 00 00    	lea    0x160(%ebx),%eax
    8799:	c7 c2 78 48 00 00    	mov    $0x4878,%edx
    879f:	66 c7 04 f2 68 00    	movw   $0x68,(%edx,%esi,8)
    87a5:	66 89 44 11 02       	mov    %ax,0x2(%ecx,%edx,1)
    87aa:	c1 c8 10             	ror    $0x10,%eax
    87ad:	88 44 11 04          	mov    %al,0x4(%ecx,%edx,1)
    87b1:	c6 44 11 05 89       	movb   $0x89,0x5(%ecx,%edx,1)
    87b6:	c6 44 11 06 00       	movb   $0x0,0x6(%ecx,%edx,1)
    87bb:	88 64 11 07          	mov    %ah,0x7(%ecx,%edx,1)
    87bf:	c1 c8 10             	ror    $0x10,%eax
    87c2:	8d 83 48 01 00 00    	lea    0x148(%ebx),%eax
    87c8:	66 c7 44 11 08 68 00 	movw   $0x68,0x8(%ecx,%edx,1)
    87cf:	66 89 44 11 0a       	mov    %ax,0xa(%ecx,%edx,1)
    87d4:	c1 c8 10             	ror    $0x10,%eax
    87d7:	88 44 11 0c          	mov    %al,0xc(%ecx,%edx,1)
    87db:	c6 44 11 0d 82       	movb   $0x82,0xd(%ecx,%edx,1)
    87e0:	c6 44 11 0e 00       	movb   $0x0,0xe(%ecx,%edx,1)
    87e5:	88 64 11 0f          	mov    %ah,0xf(%ecx,%edx,1)
    87e9:	c1 c8 10             	ror    $0x10,%eax
    87ec:	c7 c0 e0 8d 01 00    	mov    $0x18de0,%eax
    87f2:	8b 7c 24 20          	mov    0x20(%esp),%edi
    87f6:	89 1c b8             	mov    %ebx,(%eax,%edi,4)
    87f9:	8b 85 20 29 00 00    	mov    0x2920(%ebp),%eax
    87ff:	83 c4 0c             	add    $0xc,%esp
    8802:	5b                   	pop    %ebx
    8803:	5e                   	pop    %esi
    8804:	5f                   	pop    %edi
    8805:	5d                   	pop    %ebp
    8806:	c3                   	ret    
\end{lstlisting}

\subsection{init反汇编内容}
\begin{lstlisting}[breaklines]
    50d8:	f3 0f 1e fb          	endbr32 
    50dc:	56                   	push   %esi
    50dd:	53                   	push   %ebx
    50de:	83 ec 14             	sub    $0x14,%esp
    50e1:	e8 12 01 00 00       	call   0x51f8
    50e6:	81 c3 1a 1f 01 00    	add    $0x11f1a,%ebx
    50ec:	b8 00 00 00 00       	mov    $0x0,%eax
    50f1:	cd 80                	int    $0x80        sys_setup
    50f3:	85 c0                	test   %eax,%eax
    50f5:	0f 88 82 00 00 00    	js     0x517d
    50fb:	83 ec 04             	sub    $0x4,%esp
    50fe:	6a 00                	push   $0x0
    5100:	6a 02                	push   $0x2
    5102:	8d 83 00 a0 ff ff    	lea    -0x6000(%ebx),%eax
    5108:	50                   	push   %eax
    5109:	e8 69 bc 00 00       	call   0x10d77
    510e:	c7 04 24 00 00 00 00 	movl   $0x0,(%esp)
    5115:	e8 dd bc 00 00       	call   0x10df7
    511a:	c7 04 24 00 00 00 00 	movl   $0x0,(%esp)
    5121:	e8 d1 bc 00 00       	call   0x10df7
    5126:	8d 83 14 a0 ff ff    	lea    -0x5fec(%ebx),%eax
    512c:	89 44 24 1c          	mov    %eax,0x1c(%esp)
    5130:	83 c4 0c             	add    $0xc,%esp
    5133:	8d 54 24 14          	lea    0x14(%esp),%edx
    5137:	52                   	push   %edx
    5138:	50                   	push   %eax
    5139:	8d b3 80 20 00 00    	lea    0x2080(%ebx),%esi
    513f:	56                   	push   %esi
    5140:	e8 e7 2d 00 00       	call   0x7f2c
    5145:	83 c4 0c             	add    $0xc,%esp
    5148:	50                   	push   %eax
    5149:	56                   	push   %esi
    514a:	6a 01                	push   $0x1
    514c:	e8 66 bc 00 00       	call   0x10db7
    5151:	8d 83 0a a0 ff ff    	lea    -0x5ff6(%ebx),%eax
    5157:	89 44 24 1c          	mov    %eax,0x1c(%esp)
    515b:	83 c4 0c             	add    $0xc,%esp
    515e:	8d 54 24 14          	lea    0x14(%esp),%edx
    5162:	52                   	push   %edx
    5163:	50                   	push   %eax
    5164:	56                   	push   %esi
    5165:	e8 c2 2d 00 00       	call   0x7f2c
    516a:	83 c4 0c             	add    $0xc,%esp
    516d:	6a 06                	push   $0x6
    516f:	56                   	push   %esi
    5170:	6a 01                	push   $0x1
    5172:	e8 40 bc 00 00       	call   0x10db7
    5177:	83 c4 24             	add    $0x24,%esp
    517a:	5b                   	pop    %ebx
    517b:	5e                   	pop    %esi
    517c:	c3                   	ret     
\end{lstlisting}       
\subsection{sys\_setup反汇编内容}
\begin{lstlisting}[breaklines]
    9026:	f3 0f 1e fb          	endbr32 
    902a:	55                   	push   %ebp
    902b:	57                   	push   %edi
    902c:	56                   	push   %esi
    902d:	53                   	push   %ebx
    902e:	83 ec 2c             	sub    $0x2c,%esp
    9031:	e8 c2 c1 ff ff       	call   0x51f8
    9036:	81 c3 ca df 00 00    	add    $0xdfca,%ebx
    903c:	83 bb 38 00 00 00 00 	cmpl   $0x0,0x38(%ebx)
    9043:	0f 84 30 01 00 00    	je     0x9179
    9049:	c7 83 38 00 00 00 00 	movl   $0x0,0x38(%ebx)
    9050:	00 00 00 
    9053:	8d b3 e0 2d 00 00    	lea    0x2de0(%ebx),%esi
    9059:	bf 00 00 00 00       	mov    $0x0,%edi
    905e:	c7 c5 00 8f 01 00    	mov    $0x18f00,%ebp
    9064:	8d 83 8c a6 ff ff    	lea    -0x5974(%ebx),%eax
    906a:	89 44 24 1c          	mov    %eax,0x1c(%esp)
    906e:	8d 83 da a4 ff ff    	lea    -0x5b26(%ebx),%eax
    9074:	89 44 24 0c          	mov    %eax,0xc(%esp)
    9078:	89 6c 24 10          	mov    %ebp,0x10(%esp)
    907c:	8d 83 bc a6 ff ff    	lea    -0x5944(%ebx),%eax
    9082:	89 44 24 18          	mov    %eax,0x18(%esp)
    9086:	89 6c 24 14          	mov    %ebp,0x14(%esp)
    908a:	eb 70                	jmp    0x90fc
    908c:	83 ec 08             	sub    $0x8,%esp
    908f:	57                   	push   %edi
    9090:	ff 74 24 28          	pushl  0x28(%esp)
    9094:	e8 df dd ff ff       	call   0x6e78      printk
    9099:	83 c4 04             	add    $0x4,%esp
    909c:	ff 74 24 18          	pushl  0x18(%esp)
    90a0:	e8 ac df ff ff       	call   0x7051      panic
    90a5:	83 c4 10             	add    $0x10,%esp
    90a8:	eb 7d                	jmp    0x9127
    90aa:	83 ec 08             	sub    $0x8,%esp
    90ad:	57                   	push   %edi
    90ae:	ff 74 24 24          	pushl  0x24(%esp)
    90b2:	e8 c1 dd ff ff       	call   0x6e78      printk
    90b7:	83 c4 04             	add    $0x4,%esp
    90ba:	ff 74 24 18          	pushl  0x18(%esp)
    90be:	e8 8e df ff ff       	call   0x7051      panic
    90c3:	83 c4 10             	add    $0x10,%esp
    90c6:	8b 44 24 14          	mov    0x14(%esp),%eax
    90ca:	8b 00                	mov    (%eax),%eax
    90cc:	8b 10                	mov    (%eax),%edx
    90ce:	b8 00 00 00 00       	mov    $0x0,%eax
    90d3:	8b 8c 42 c6 01 00 00 	mov    0x1c6(%edx,%eax,2),%ecx
    90da:	89 4c 06 08          	mov    %ecx,0x8(%esi,%eax,1)
    90de:	8b 8c 42 ca 01 00 00 	mov    0x1ca(%edx,%eax,2),%ecx
    90e5:	89 4c 06 0c          	mov    %ecx,0xc(%esi,%eax,1)
    90e9:	83 c0 08             	add    $0x8,%eax
    90ec:	83 f8 20             	cmp    $0x20,%eax
    90ef:	75 e2                	jne    0x90d3
    90f1:	83 c7 01             	add    $0x1,%edi
    90f4:	83 c6 28             	add    $0x28,%esi
    90f7:	83 ff 02             	cmp    $0x2,%edi
    90fa:	74 52                	je     0x914e
    90fc:	83 ec 04             	sub    $0x4,%esp
    90ff:	ff 75 00             	pushl  0x0(%ebp)
    9102:	6a 00                	push   $0x0
    9104:	6a 00                	push   $0x0
    9106:	b9 01 00 00 00       	mov    $0x1,%ecx
    910b:	89 fa                	mov    %edi,%edx
    910d:	b8 00 00 00 00       	mov    $0x0,%eax
    9112:	e8 49 fa ff ff       	call   0x8b60    rw_abs_hd
    9117:	8b 45 00             	mov    0x0(%ebp),%eax
    911a:	83 c4 10             	add    $0x10,%esp
    911d:	80 78 08 00          	cmpb   $0x0,0x8(%eax)
    9121:	0f 84 65 ff ff ff    	je     0x908c
    9127:	8b 44 24 10          	mov    0x10(%esp),%eax
    912b:	8b 00                	mov    (%eax),%eax
    912d:	8b 00                	mov    (%eax),%eax
    912f:	80 b8 fe 01 00 00 55 	cmpb   $0x55,0x1fe(%eax)
    9136:	0f 85 6e ff ff ff    	jne    0x90aa
    913c:	80 b8 ff 01 00 00 aa 	cmpb   $0xaa,0x1ff(%eax)
    9143:	0f 85 61 ff ff ff    	jne    0x90aa
    9149:	e9 78 ff ff ff       	jmp    0x90c6
    914e:	83 ec 08             	sub    $0x8,%esp
    9151:	8d 83 76 a3 ff ff    	lea    -0x5c8a(%ebx),%eax
    9157:	50                   	push   %eax
    9158:	8d 83 db a4 ff ff    	lea    -0x5b25(%ebx),%eax
    915e:	50                   	push   %eax
    915f:	e8 14 dd ff ff       	call   0x6e78     printk
    9164:	e8 8c 2b 00 00       	call   0xbcf5     mount_root
    9169:	83 c4 10             	add    $0x10,%esp
    916c:	b8 00 00 00 00       	mov    $0x0,%eax
    9171:	83 c4 2c             	add    $0x2c,%esp
    9174:	5b                   	pop    %ebx
    9175:	5e                   	pop    %esi
    9176:	5f                   	pop    %edi
    9177:	5d                   	pop    %ebp
    9178:	c3                   	ret    
    9179:	b8 ff ff ff ff       	mov    $0xffffffff,%eax
    917e:	eb f1                	jmp    0x9171
\end{lstlisting}
\subsection{rw\_abs\_hd(反汇编内容}
\begin{lstlisting}[breaklines]
    8b60:	55                   	push   %ebp
    8b61:	57                   	push   %edi
    8b62:	56                   	push   %esi
    8b63:	53                   	push   %ebx
    8b64:	83 ec 1c             	sub    $0x1c,%esp
    8b67:	e8 8c c6 ff ff       	call   0x51f8
    8b6c:	81 c3 94 e4 00 00    	add    $0xe494,%ebx
    8b72:	89 44 24 08          	mov    %eax,0x8(%esp)
    8b76:	89 d7                	mov    %edx,%edi
    8b78:	89 cd                	mov    %ecx,%ebp
    8b7a:	83 f8 01             	cmp    $0x1,%eax
    8b7d:	77 1a                	ja     0x8b99
    8b7f:	8b 44 24 38          	mov    0x38(%esp),%eax
    8b83:	80 78 0b 00          	cmpb   $0x0,0xb(%eax)
    8b87:	75 24                	jne    0x8bad
    8b89:	8b 44 24 38          	mov    0x38(%esp),%eax
    8b8d:	c6 40 0b 01          	movb   $0x1,0xb(%eax)
    8b91:	8d b3 e0 2d 00 00    	lea    0x2de0(%ebx),%esi
    8b97:	eb 3e                	jmp    0x8bd7
    8b99:	83 ec 0c             	sub    $0xc,%esp
    8b9c:	8d 83 a1 a4 ff ff    	lea    -0x5b5f(%ebx),%eax
    8ba2:	50                   	push   %eax
    8ba3:	e8 a9 e4 ff ff       	call   0x7051      panic
    8ba8:	83 c4 10             	add    $0x10,%esp
    8bab:	eb d2                	jmp    0x8b7f
    8bad:	83 ec 0c             	sub    $0xc,%esp
    8bb0:	8d 83 bd a4 ff ff    	lea    -0x5b43(%ebx),%eax
    8bb6:	50                   	push   %eax
    8bb7:	e8 bc e2 ff ff       	call   0x6e78      printk
    8bbc:	83 c4 10             	add    $0x10,%esp
    8bbf:	eb c8                	jmp    0x8b89
    8bc1:	39 f0                	cmp    %esi,%eax
    8bc3:	75 26                	jne    0x8beb
    8bc5:	83 ec 0c             	sub    $0xc,%esp
    8bc8:	8d 83 44 29 00 00    	lea    0x2944(%ebx),%eax
    8bce:	50                   	push   %eax
    8bcf:	e8 9d c7 ff ff       	call   0x5371      sleep_on
    8bd4:	83 c4 10             	add    $0x10,%esp
    8bd7:	8d 83 60 29 00 00    	lea    0x2960(%ebx),%eax
    8bdd:	83 38 00             	cmpl   $0x0,(%eax)
    8be0:	78 df                	js     0x8bc1
    8be2:	83 c0 24             	add    $0x24,%eax
    8be5:	39 f0                	cmp    %esi,%eax
    8be7:	75 f4                	jne    0x8bdd
    8be9:	eb da                	jmp    0x8bc5
    8beb:	89 fe                	mov    %edi,%esi
    8bed:	89 38                	mov    %edi,(%eax)
    8bef:	c7 40 04 02 00 00 00 	movl   $0x2,0x4(%eax)
    8bf6:	89 6c 24 0c          	mov    %ebp,0xc(%esp)
    8bfa:	89 68 08             	mov    %ebp,0x8(%eax)
    8bfd:	8b 4c 24 30          	mov    0x30(%esp),%ecx
    8c01:	89 4c 24 04          	mov    %ecx,0x4(%esp)
    8c05:	89 48 0c             	mov    %ecx,0xc(%eax)
    8c08:	8b 54 24 34          	mov    0x34(%esp),%edx
    8c0c:	89 d5                	mov    %edx,%ebp
    8c0e:	89 50 10             	mov    %edx,0x10(%eax)
    8c11:	83 7c 24 08 01       	cmpl   $0x1,0x8(%esp)
    8c16:	19 d2                	sbb    %edx,%edx
    8c18:	83 e2 f0             	and    $0xfffffff0,%edx
    8c1b:	83 c2 30             	add    $0x30,%edx
    8c1e:	89 50 14             	mov    %edx,0x14(%eax)
    8c21:	8b 4c 24 38          	mov    0x38(%esp),%ecx
    8c25:	89 48 1c             	mov    %ecx,0x1c(%eax)
    8c28:	c7 40 18 00 00 00 00 	movl   $0x0,0x18(%eax)
    8c2f:	c7 40 20 00 00 00 00 	movl   $0x0,0x20(%eax)
    8c36:	c7 83 48 29 00 00 01 	movl   $0x1,0x2948(%ebx)
    8c3d:	00 00 00 
    8c40:	8b 93 4c 29 00 00    	mov    0x294c(%ebx),%edx
    8c46:	85 d2                	test   %edx,%edx
    8c48:	74 18                	je     0x8c62
    8c4a:	8b 7a 20             	mov    0x20(%edx),%edi
    8c4d:	85 ff                	test   %edi,%edi
    8c4f:	74 1c                	je     0x8c6d
    8c51:	8b 57 20             	mov    0x20(%edi),%edx
    8c54:	85 d2                	test   %edx,%edx
    8c56:	0f 84 ae 00 00 00    	je     0x8d0a
    8c5c:	89 44 24 08          	mov    %eax,0x8(%esp)
    8c60:	eb 4b                	jmp    0x8cad
    8c62:	89 83 4c 29 00 00    	mov    %eax,0x294c(%ebx)
    8c68:	e9 a3 00 00 00       	jmp    0x8d10
    8c6d:	89 42 20             	mov    %eax,0x20(%edx)
    8c70:	e9 9b 00 00 00       	jmp    0x8d10
    8c75:	8b 4f 10             	mov    0x10(%edi),%ecx
    8c78:	39 cd                	cmp    %ecx,%ebp
    8c7a:	7f 1a                	jg     0x8c96
    8c7c:	75 37                	jne    0x8cb5
    8c7e:	8b 4f 0c             	mov    0xc(%edi),%ecx
    8c81:	39 4c 24 04          	cmp    %ecx,0x4(%esp)
    8c85:	7f 0f                	jg     0x8c96
    8c87:	39 4c 24 04          	cmp    %ecx,0x4(%esp)
    8c8b:	75 28                	jne    0x8cb5
    8c8d:	8b 4c 24 0c          	mov    0xc(%esp),%ecx
    8c91:	3b 4f 08             	cmp    0x8(%edi),%ecx
    8c94:	7e 1f                	jle    0x8cb5
    8c96:	8b 02                	mov    (%edx),%eax
    8c98:	39 c6                	cmp    %eax,%esi
    8c9a:	0f 8c ae 00 00 00    	jl     0x8d4e
    8ca0:	74 3d                	je     0x8cdf
    8ca2:	8b 4a 20             	mov    0x20(%edx),%ecx
    8ca5:	89 d7                	mov    %edx,%edi
    8ca7:	85 c9                	test   %ecx,%ecx
    8ca9:	74 59                	je     0x8d04
    8cab:	89 ca                	mov    %ecx,%edx
    8cad:	8b 07                	mov    (%edi),%eax
    8caf:	39 c6                	cmp    %eax,%esi
    8cb1:	7f e3                	jg     0x8c96
    8cb3:	74 c0                	je     0x8c75
    8cb5:	8b 0a                	mov    (%edx),%ecx
    8cb7:	39 c8                	cmp    %ecx,%eax
    8cb9:	7c e7                	jl     0x8ca2
    8cbb:	75 d9                	jne    0x8c96
    8cbd:	8b 4f 10             	mov    0x10(%edi),%ecx
    8cc0:	8b 42 10             	mov    0x10(%edx),%eax
    8cc3:	39 c1                	cmp    %eax,%ecx
    8cc5:	7c db                	jl     0x8ca2
    8cc7:	75 cd                	jne    0x8c96
    8cc9:	8b 4f 0c             	mov    0xc(%edi),%ecx
    8ccc:	8b 42 0c             	mov    0xc(%edx),%eax
    8ccf:	39 c1                	cmp    %eax,%ecx
    8cd1:	7c cf                	jl     0x8ca2
    8cd3:	75 c1                	jne    0x8c96
    8cd5:	8b 42 08             	mov    0x8(%edx),%eax
    8cd8:	39 47 08             	cmp    %eax,0x8(%edi)
    8cdb:	7c c5                	jl     0x8ca2
    8cdd:	eb b7                	jmp    0x8c96
    8cdf:	8b 42 10             	mov    0x10(%edx),%eax
    8ce2:	39 c5                	cmp    %eax,%ebp
    8ce4:	7c 6e                	jl     0x8d54
    8ce6:	75 ba                	jne    0x8ca2
    8ce8:	8b 42 0c             	mov    0xc(%edx),%eax
    8ceb:	8b 4c 24 04          	mov    0x4(%esp),%ecx
    8cef:	39 c1                	cmp    %eax,%ecx
    8cf1:	7c 67                	jl     0x8d5a
    8cf3:	75 ad                	jne    0x8ca2
    8cf5:	8b 44 24 0c          	mov    0xc(%esp),%eax
    8cf9:	3b 42 08             	cmp    0x8(%edx),%eax
    8cfc:	7d a4                	jge    0x8ca2
    8cfe:	8b 44 24 08          	mov    0x8(%esp),%eax
    8d02:	eb 06                	jmp    0x8d0a
    8d04:	8b 44 24 08          	mov    0x8(%esp),%eax
    8d08:	89 ca                	mov    %ecx,%edx
    8d0a:	89 50 20             	mov    %edx,0x20(%eax)
    8d0d:	89 47 20             	mov    %eax,0x20(%edi)
    8d10:	c7 83 48 29 00 00 00 	movl   $0x0,0x2948(%ebx)
    8d17:	00 00 00 
    8d1a:	83 bb 40 29 00 00 00 	cmpl   $0x0,0x2940(%ebx)
    8d21:	74 3d                	je     0x8d60
    8d23:	fa                   	cli    
    8d24:	8b 44 24 38          	mov    0x38(%esp),%eax
    8d28:	80 78 0b 00          	cmpb   $0x0,0xb(%eax)
    8d2c:	74 17                	je     0x8d45
    8d2e:	8d 70 0c             	lea    0xc(%eax),%esi
    8d31:	89 c7                	mov    %eax,%edi
    8d33:	83 ec 0c             	sub    $0xc,%esp
    8d36:	56                   	push   %esi
    8d37:	e8 35 c6 ff ff       	call   0x5371      sleep_on
    8d3c:	83 c4 10             	add    $0x10,%esp
    8d3f:	80 7f 0b 00          	cmpb   $0x0,0xb(%edi)
    8d43:	75 ee                	jne    0x8d33
    8d45:	fb                   	sti    
    8d46:	83 c4 1c             	add    $0x1c,%esp
    8d49:	5b                   	pop    %ebx
    8d4a:	5e                   	pop    %esi
    8d4b:	5f                   	pop    %edi
    8d4c:	5d                   	pop    %ebp
    8d4d:	c3                   	ret     
    8d4e:	8b 44 24 08          	mov    0x8(%esp),%eax
    8d52:	eb b6                	jmp    0x8d0a
    8d54:	8b 44 24 08          	mov    0x8(%esp),%eax
    8d58:	eb b0                	jmp    0x8d0a
    8d5a:	8b 44 24 08          	mov    0x8(%esp),%eax
    8d5e:	eb aa                	jmp    0x8d0a
    8d60:	e8 09 fd ff ff       	call   0x8a6e   do_request
    8d65:	eb bc                	jmp    0x8d23    
\end{lstlisting}    
\subsection{do\_request反汇编内容}
\begin{lstlisting}[breaklines]
    8a6e:	f3 0f 1e fb          	endbr32 
    8a72:	56                   	push   %esi
    8a73:	53                   	push   %ebx
    8a74:	83 ec 04             	sub    $0x4,%esp
    8a77:	e8 7c c7 ff ff       	call   0x51f8
    8a7c:	81 c3 84 e5 00 00    	add    $0xe584,%ebx
    8a82:	83 bb 48 29 00 00 00 	cmpl   $0x0,0x2948(%ebx)
    8a89:	75 29                	jne    0x8ab4
    8a8b:	8b 83 4c 29 00 00    	mov    0x294c(%ebx),%eax
    8a91:	85 c0                	test   %eax,%eax
    8a93:	74 25                	je     0x8aba
    8a95:	8b 50 14             	mov    0x14(%eax),%edx
    8a98:	83 fa 30             	cmp    $0x30,%edx
    8a9b:	74 29                	je     0x8ac6
    8a9d:	83 fa 20             	cmp    $0x20,%edx
    8aa0:	74 73                	je     0x8b15
    8aa2:	83 ec 0c             	sub    $0xc,%esp
    8aa5:	8d 83 8e a4 ff ff    	lea    -0x5b72(%ebx),%eax
    8aab:	50                   	push   %eax
    8aac:	e8 a0 e5 ff ff       	call   0x7051      panic
    8ab1:	83 c4 10             	add    $0x10,%esp
    8ab4:	83 c4 04             	add    $0x4,%esp
    8ab7:	5b                   	pop    %ebx
    8ab8:	5e                   	pop    %esi
    8ab9:	c3                   	ret    
    8aba:	c7 83 40 29 00 00 00 	movl   $0x0,0x2940(%ebx)
    8ac1:	00 00 00 
    8ac4:	eb ee                	jmp    0x8ab4
    8ac6:	8b 48 08             	mov    0x8(%eax),%ecx
    8ac9:	8b 50 04             	mov    0x4(%eax),%edx
    8acc:	8d b3 c2 1e ff ff    	lea    -0xe13e(%ebx),%esi
    8ad2:	56                   	push   %esi
    8ad3:	6a 30                	push   $0x30
    8ad5:	ff 70 10             	pushl  0x10(%eax)
    8ad8:	ff 70 0c             	pushl  0xc(%eax)
    8adb:	8b 00                	mov    (%eax),%eax
    8add:	e8 f4 fd ff ff       	call   0x88d6       hd_out
    8ae2:	ba f7 01 00 00       	mov    $0x1f7,%edx
    8ae7:	ec                   	in     (%dx),%al
    8ae8:	eb 00                	jmp    0x8aea
    8aea:	eb 00                	jmp    0x8aec
    8aec:	83 c4 10             	add    $0x10,%esp
    8aef:	b9 b7 0b 00 00       	mov    $0xbb7,%ecx
    8af4:	a8 08                	test   $0x8,%al
    8af6:	75 41                	jne    0x8b39
    8af8:	ec                   	in     (%dx),%al
    8af9:	eb 00                	jmp    0x8afb
    8afb:	eb 00                	jmp    0x8afd
    8afd:	a8 08                	test   $0x8,%al
    8aff:	75 38                	jne    0x8b39
    8b01:	83 e9 01             	sub    $0x1,%ecx
    8b04:	75 f2                	jne    0x8af8
    8b06:	8b 83 4c 29 00 00    	mov    0x294c(%ebx),%eax
    8b0c:	8b 00                	mov    (%eax),%eax
    8b0e:	e8 ad fe ff ff       	call   0x89c0      reset_hd
    8b13:	eb 9f                	jmp    0x8ab4
    8b15:	8b 48 08             	mov    0x8(%eax),%ecx
    8b18:	8b 50 04             	mov    0x4(%eax),%edx
    8b1b:	8d 9b f2 1d ff ff    	lea    -0xe20e(%ebx),%ebx
    8b21:	53                   	push   %ebx
    8b22:	6a 20                	push   $0x20
    8b24:	ff 70 10             	pushl  0x10(%eax)
    8b27:	ff 70 0c             	pushl  0xc(%eax)
    8b2a:	8b 00                	mov    (%eax),%eax
    8b2c:	e8 a5 fd ff ff       	call   0x88d6       hd_out
    8b31:	83 c4 10             	add    $0x10,%esp
    8b34:	e9 7b ff ff ff       	jmp    0x8ab4
    8b39:	8b 83 4c 29 00 00    	mov    0x294c(%ebx),%eax
    8b3f:	8b 50 1c             	mov    0x1c(%eax),%edx
    8b42:	8b 70 04             	mov    0x4(%eax),%esi
    8b45:	83 e6 01             	and    $0x1,%esi
    8b48:	c1 e6 09             	shl    $0x9,%esi
    8b4b:	03 32                	add    (%edx),%esi
    8b4d:	ba f0 01 00 00       	mov    $0x1f0,%edx
    8b52:	b9 00 01 00 00       	mov    $0x100,%ecx
    8b57:	fc                   	cld    
    8b58:	f3 66 6f             	rep outsw %ds:(%esi),(%dx)
    8b5b:	e9 54 ff ff ff       	jmp    0x8ab4     
\end{lstlisting}    
\subsection{hd\_out反汇编内容}
\begin{lstlisting}[breaklines]
    88d6:	55                   	push   %ebp
    88d7:	57                   	push   %edi
    88d8:	56                   	push   %esi
    88d9:	53                   	push   %ebx
    88da:	83 ec 0c             	sub    $0xc,%esp
    88dd:	e8 16 c9 ff ff       	call   0x51f8
    88e2:	81 c3 1e e7 00 00    	add    $0xe71e,%ebx
    88e8:	89 c6                	mov    %eax,%esi
    88ea:	89 d5                	mov    %edx,%ebp
    88ec:	89 cf                	mov    %ecx,%edi
    88ee:	83 f8 01             	cmp    $0x1,%eax
    88f1:	0f 87 b2 00 00 00    	ja     0x89a9
    88f7:	83 7c 24 20 0f       	cmpl   $0xf,0x20(%esp)
    88fc:	0f 87 a7 00 00 00    	ja     0x89a9
    8902:	b9 e7 03 00 00       	mov    $0x3e7,%ecx
    8907:	ba f7 01 00 00       	mov    $0x1f7,%edx
    890c:	ec                   	in     (%dx),%al    controller_ready()
    890d:	83 e0 c0             	and    $0xffffffc0,%eax
    8910:	3c 40                	cmp    $0x40,%al
    8912:	74 17                	je     0x892b
    8914:	83 e9 01             	sub    $0x1,%ecx
    8917:	75 f3                	jne    0x890c
    8919:	83 ec 0c             	sub    $0xc,%esp    not_ready
    891c:	8d 83 5b a4 ff ff    	lea    -0x5ba5(%ebx),%eax
    8922:	50                   	push   %eax
    8923:	e8 29 e7 ff ff       	call   0x7051      panic
    8928:	83 c4 10             	add    $0x10,%esp
    892b:	8b 44 24 2c          	mov    0x2c(%esp),%eax
    892f:	89 83 40 29 00 00    	mov    %eax,0x2940(%ebx)
    8935:	b8 00 00 00 00       	mov    $0x0,%eax
    893a:	ba f6 03 00 00       	mov    $0x3f6,%edx
    893f:	ee                   	out    %al,(%dx)
    8940:	ba f1 01 00 00       	mov    $0x1f1,%edx
    8945:	b8 4b 00 00 00       	mov    $0x4b,%eax
    894a:	ee                   	out    %al,(%dx)
    894b:	eb 00                	jmp    0x894d
    894d:	eb 00                	jmp    0x894f
    894f:	ba f2 01 00 00       	mov    $0x1f2,%edx
    8954:	89 e8                	mov    %ebp,%eax
    8956:	ee                   	out    %al,(%dx)
    8957:	eb 00                	jmp    0x8959
    8959:	eb 00                	jmp    0x895b
    895b:	ba f3 01 00 00       	mov    $0x1f3,%edx
    8960:	89 f8                	mov    %edi,%eax
    8962:	ee                   	out    %al,(%dx)
    8963:	eb 00                	jmp    0x8965
    8965:	eb 00                	jmp    0x8967
    8967:	ba f4 01 00 00       	mov    $0x1f4,%edx
    896c:	8b 44 24 24          	mov    0x24(%esp),%eax
    8970:	ee                   	out    %al,(%dx)
    8971:	eb 00                	jmp    0x8973
    8973:	eb 00                	jmp    0x8975
    8975:	c1 e8 08             	shr    $0x8,%eax
    8978:	ba f5 01 00 00       	mov    $0x1f5,%edx
    897d:	ee                   	out    %al,(%dx)
    897e:	eb 00                	jmp    0x8980
    8980:	eb 00                	jmp    0x8982
    8982:	89 f0                	mov    %esi,%eax
    8984:	c1 e0 04             	shl    $0x4,%eax
    8987:	0b 44 24 20          	or     0x20(%esp),%eax
    898b:	0c a0                	or     $0xa0,%al
    898d:	ba f6 01 00 00       	mov    $0x1f6,%edx
    8992:	ee                   	out    %al,(%dx)
    8993:	eb 00                	jmp    0x8995
    8995:	eb 00                	jmp    0x8997
    8997:	ba f7 01 00 00       	mov    $0x1f7,%edx
    899c:	8b 44 24 28          	mov    0x28(%esp),%eax
    89a0:	ee                   	out    %al,(%dx)
    89a1:	83 c4 0c             	add    $0xc,%esp
    89a4:	5b                   	pop    %ebx
    89a5:	5e                   	pop    %esi
    89a6:	5f                   	pop    %edi
    89a7:	5d                   	pop    %ebp
    89a8:	c3                   	ret     
\end{lstlisting}   
\subsection{hd\_interrupt反汇编内容}
\begin{lstlisting}[breaklines]    
    7018:	50                   	push   %eax
    7019:	51                   	push   %ecx
    701a:	52                   	push   %edx
    701b:	1e                   	push   %ds
    701c:	06                   	push   %es
    701d:	0f a0                	push   %fs
    701f:	b8 10 00 00 00       	mov    $0x10,%eax
    7024:	8e d8                	mov    %eax,%ds
    7026:	8e c0                	mov    %eax,%es
    7028:	b8 17 00 00 00       	mov    $0x17,%eax
    702d:	8e e0                	mov    %eax,%fs
    702f:	b0 20                	mov    $0x20,%al
    7031:	e6 20                	out    %al,$0x20
    7033:	eb 00                	jmp    0x7035
    7035:	eb 00                	jmp    0x7037
    7037:	e6 a0                	out    %al,$0xa0
    7039:	a1 40 99 01 00       	mov    0x19940,%eax
    703e:	85 c0                	test   %eax,%eax
    7040:	75 05                	jne    0x7047
    7042:	b8 80 91 00 00       	mov    $0x9180,%eax
    7047:	ff d0                	call   *%eax
    7049:	0f a1                	pop    %fs
    704b:	07                   	pop    %es
    704c:	1f                   	pop    %ds
    704d:	5a                   	pop    %edx
    704e:	59                   	pop    %ecx
    704f:	58                   	pop    %eax
    7050:	cf                   	iret   


50d8, init
5100, main
5161, init

51bc, schedule      
52ae, switch to next
9196, hd init
700c, hd interrupt
8de6, read_intr
8873, win_result
0x8d58 =   0b1000110101011000
buzy 0x80= 0b0000000010000000
ready0x40= 0b0000000001000000 ok
werr 0x20= 0b0000000000100000
seek 0x10= 0b0000000000010000 ok
err  0x01= 0b0000000000000001

9cf7, sys open
6e78, printk
7f2c, vsprintf
80f8, case s

ea87 open_namei
e8ce dir_namei
e668 get_dir
e092 get_fs_byte

s=3 17+2 = 19
512*19 = 2600h

s=5 17+4 = 21
512*21 = 2a00h

s=7 17+6 = 23
512*23 = 2e00

s= 9 17+8 = 25
512 * 25 = 3200h

h=1 cyl=0 s=17 17+16 = 33
512*33 = 0x4200

h=2 cyl=0 s=2
17+16+2=35
512*35 = 0x4600


objdump tools/system -dSsx > system.s
0x0001200a -- ok.  0x2e6b4f20
vb 
\end{lstlisting}   

\end{CJK}
\end{document}
